---
title: "Canadian Election Study"
author: "Mathieu Lavigne"
date: "2026-04-07"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Set working directory and load packages

```{r}
# Set working directory
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))

# Load packages (remove # and run first two lines if pacman and cesR package not already installed)
# install.packages("pacman")
# devtools::install_github("hodgettsp/cesR")
pacman::p_load(cesR, haven, survey, scales, modelsummary, marginaleffects, jtools, estimatr, ggpubr, lubridate, patchwork, tidyverse, Hmisc)
```

## Create folders for tables and figures

```{r}
if (!dir.exists("Figures")) {
  dir.create("Figures")
  message("Created 'Figures' folder.")
} else {
  message("'Figures' folder already exists.")
}

if (!dir.exists("Tables")) {
  dir.create("Tables")
  message("Created 'Tables' folder.")
} else {
  message("'Tables' folder already exists.")
}
```

## Functions

```{r}
summarize_weighted <- function(data, dv, ivs, weight_var, group_vars = NULL, var_label = NULL, filter_expr = NULL) {
  
  # Optionally filter the data
  if (!is.null(filter_expr)) {
    data <- data %>% filter(!!rlang::parse_expr(filter_expr))
  }
  
  # Select variables
  vars_to_select <- c(ivs, dv, weight_var)
  data <- data %>% dplyr::select(all_of(vars_to_select)) %>% na.omit()
  
  # Group by IVs and any additional grouping
  group_vars <- if (is.null(group_vars)) ivs else c(ivs, group_vars)
  
  data %>%
    group_by(across(all_of(group_vars))) %>%
    dplyr::summarize(
      value = weighted.mean(.data[[dv]], w = .data[[weight_var]]),
      sd = sqrt(wtd.var(.data[[dv]], weights = .data[[weight_var]])),
      n = n(),
      .groups = "drop"
    ) %>%
    mutate(
      var = var_label,
      se = sd / sqrt(n),
      lower = value - 1.96 * se,
      upper = value + 1.96 * se
    )
}
```

## Load data

```{r}
# Load 2008-2015 CES using cesR package
get_ces("ces2008")
get_ces("ces2011")
get_ces("ces2015_phone")
get_ces("ces2019_web")
get_ces("ces2019_phone")

# Load 2019 and 2021 CES
ces2019 <- read_dta("./CES-E-2019-online_F1.dta", encoding = "latin1")
ces2021 <- read_dta("./2021 Canadian Election Study v2.0.dta")
```

## Recode data

2008 election

```{r}
ces08 <- ces2008 %>% 
  mutate(
    # Election year
    year=2008,
    # Trust in election administration (full scale)
    satisfied = case_when(
      ces08_PES_B11==1 ~ 1,
      ces08_PES_B11==3 ~ 0.67,
      ces08_PES_B11==5 ~ 0.33,
      ces08_PES_B11==7 ~ 0,
      TRUE ~ NA_real_),
    confidence = case_when(
      ces08_MBS_DL==1 ~ 1,
      ces08_MBS_DL==2 ~ 0.67,
      ces08_MBS_DL==3 ~ 0.33,
      ces08_MBS_DL==4 ~ 0,
      TRUE ~ NA_real_),
    fairly = case_when(
      ces08_MBS_K1==1 ~ 1,
      ces08_MBS_K1==2 ~ 0.67,
      ces08_MBS_K1==3 ~ 0.33,
      ces08_MBS_K1==4 ~ 0,
      TRUE ~ NA_real_),
    # Trust in election administration (dummy)
    satisfied01 = ifelse(satisfied > 0.5, 1, 0),
    confidence01 = ifelse(confidence > 0.5, 1, 0),
    fairly01 = ifelse(fairly > 0.5, 1, 0),
    # Ideology and vote choice
    ideol = ifelse(!ces08_MBS_I12 %in% c(0:10), NA, ces08_MBS_I12),
    vote_choice = case_when(
      ces08_PES_B4B == 1 ~ "Liberal",
      ces08_PES_B4B == 2 ~ "Conservative",
      ces08_PES_B4B == 3 ~ "NDP",
      ces08_PES_B4B == 4 ~ "BQ",
      ces08_PES_B4B == 5 ~ "Green",
      TRUE ~ NA_character_),
    vote_lpc = ifelse(vote_choice == "Liberal", 1, 0),
    vote_cpc = ifelse(vote_choice == "Conservative", 2, 0),
    vote_ndp = ifelse(vote_choice == "NDP", 3, 0),
    vote_bq = ifelse(vote_choice == "BQ", 4, 0),
    vote_green = ifelse(vote_choice == "Green", 5, 0),
    vote_winner = case_when(
      ces08_PES_B4B == 2 ~ 1,
      ces08_PES_B4B %in% c(1,3,4,5) ~ 0,
      TRUE ~ NA_real_),
    # Affective polarization
    feeling_winner = ifelse(!ces08_CPS_G7 %in% c(0:100), NA, ces08_CPS_G7),
    feeling_lib = ifelse(!ces08_CPS_G8 %in% c(0:100), NA, ces08_CPS_G8),
    feeling_con = ifelse(!ces08_CPS_G7 %in% c(0:100), NA, ces08_CPS_G7),
    feeling_ndp = ifelse(!ces08_CPS_G9 %in% c(0:100), NA, ces08_CPS_G9),
    feeling_bq = ifelse(!ces08_CPS_G10 %in% c(0:100), NA, ces08_CPS_G10),
    feeling_green = ifelse(!ces08_CPS_G11 %in% c(0:100), NA, ces08_CPS_G11),
    feeling_ppc = NA,
    aff_pol_libcon = abs(feeling_lib-feeling_con),
    aff_pol_ndp_winner = abs(feeling_ndp-feeling_winner),
    aff_pol_bq_winner = abs(feeling_bq-feeling_winner),
    aff_pol_green_winner = abs(feeling_green-feeling_winner),
    aff_pol_ppc_winner = NA,
    aff_pol_with_winner = case_when(
      vote_choice == "Liberal" ~ aff_pol_libcon,
      vote_choice == "Conservative" ~ NA_real_,
      vote_choice == "NDP" ~ aff_pol_ndp_winner,
      vote_choice == "BQ" ~ aff_pol_bq_winner,
      vote_choice == "Green" ~ aff_pol_green_winner,
    ),
    # Affective polarization: Weighted spread of affects
    share_lib = 0.2626,
    share_con = 0.3765,
    share_ndp = 0.1818,
    share_bq = 0.0998,
    share_green = 0.0678,
    share_ppc = NA,
    weight_lib = feeling_lib*share_lib,
    weight_con = feeling_con*share_con,
    weight_ndp = feeling_ndp*share_ndp,
    weight_bq =  feeling_bq*share_bq,
    weight_green = feeling_green*share_green,
    weight_ppc =   NA,
    mean_affect = weight_lib+weight_con+weight_ndp+weight_bq+weight_green,
    distance_lib = (feeling_lib-mean_affect)^2,
    distance_con = (feeling_con-mean_affect)^2,
    distance_ndp = (feeling_ndp-mean_affect)^2,
    distance_bq = (feeling_bq-mean_affect)^2,
    distance_green = (feeling_green-mean_affect)^2,
    distance_ppc = NA,
    wt_sq_lib = distance_lib*share_lib,
    wt_sq_con = distance_con*share_con,
    wt_sq_ndp = distance_ndp*share_ndp,
    wt_sq_bq = distance_bq*share_bq,
    wt_sq_green = distance_green*share_green,
    wt_sq_ppc = NA,
    sum_polariz = wt_sq_lib+wt_sq_con+wt_sq_ndp+wt_sq_bq+wt_sq_green,
    spread_affect = sqrt(sum_polariz),
    # Socio-demographic characteristics
    interest  = ifelse(!ces08_CPS_A4 %in% c(0:10), NA, ces08_CPS_A4),
    female = ifelse(GENDER == 1, 0, 1),
    male = ifelse(GENDER == 5, 0, 1),
    age = ifelse(YEARofBIRTH != 9998 & YEARofBIRTH != 9999,  2008-YEARofBIRTH, NA),
    age_cat = case_when(
      age >= 18 & age < 25 ~ 0,
      age >= 25 & age < 35 ~ 0.2,
      age >= 35 & age < 45 ~ 0.4,
      age >= 45 & age < 55 ~ 0.6,
      age >= 55 & age < 65 ~ 0.8,
      age >= 65 ~ 1,
      TRUE ~ NA_real_),
    age18_29 =ifelse(age >= 18 & age < 30, 1, 0),
    age30_44 =ifelse(age >= 30 & age < 45, 1, 0),
    age45_59 =ifelse(age >= 45 & age < 60, 1, 0),
    age60_ =ifelse(age >= 60, 1, 0),
    educ_cat = case_when(
      ces08_CPS_S3 %in% c(1:6) ~ 0, 
      ces08_CPS_S3 %in% c(7:8) ~ 0.5,
      ces08_CPS_S3 %in% c(9:11) ~ 1, 
      TRUE ~ NA_real_), 
    highschool = ifelse(ces08_CPS_S3 %in% c(1:6), 1, 0),
    college = ifelse(ces08_CPS_S3 %in% c(7:8), 1, 0),
    university = ifelse(ces08_CPS_S3 %in% c(9:11), 1, 0),
    region = case_when(
      ces08_PROVINCE %in% c(10:13) ~ "Atlantic",
      ces08_PROVINCE ==24 ~ "Quebec",
      ces08_PROVINCE ==35 ~ "Ontario",
      ces08_PROVINCE %in% c(46:48) ~ "Prairies",
      ces08_PROVINCE ==59 ~ "British Columbia",
      TRUE ~ NA_character_),
    Atlantic=ifelse(region=="Atlantic", 1, 0),
    Quebec=ifelse(region=="Quebec", 1, 0),
    Ontario=ifelse(region=="Ontario", 1, 0),
    Prairies=ifelse(region=="Prairies", 1, 0),
    BC=ifelse(region=="British Columbia", 1, 0),
    province = case_when(
      ces08_PROVINCE ==10 ~ "Newfoundland",
      ces08_PROVINCE ==11 ~ "PEI",
      ces08_PROVINCE ==12 ~ "Nova Scotia",
      ces08_PROVINCE ==13 ~ "New Brunswick",
      ces08_PROVINCE ==24 ~ "Quebec",
      ces08_PROVINCE ==35 ~ "Ontario",
      ces08_PROVINCE ==46 ~ "Manitoba",
      ces08_PROVINCE ==47 ~ "Saskatchewan",
      ces08_PROVINCE ==48 ~ "Alberta",
      ces08_PROVINCE ==59 ~ "British Columbia", 
    ),
    # Trust in mail voting
    mail_distrust = NA,
    mail_distrust01 = NA,
    # Alternative explanations: Voting experiences
    satisf_voting = NA,
    satisf_voting01 = NA,
    turnout=NA,
    # Alternative explanations: Generalized decline in trust
    trust_pub_serv = case_when(
      ces08_MBS_DE == 1 ~ 1,
      ces08_MBS_DE == 2 ~ 0.67,
      ces08_MBS_DE == 3 ~ 0.33,
      ces08_MBS_DE == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_media = case_when(
      ces08_MBS_DK == 1 ~ 1,
      ces08_MBS_DK == 2 ~ 0.67,
      ces08_MBS_DK == 3 ~ 0.33,
      ces08_MBS_DK == 4 ~ 0,
      TRUE ~ NA_real_ 
    ),
    trust_fedgov = case_when(
      ces08_MBS_DH == 1 ~ 1,
      ces08_MBS_DH == 2 ~ 0.67,
      ces08_MBS_DH == 3 ~ 0.33,
      ces08_MBS_DH == 4 ~ 0,
      TRUE ~ NA_real_ 
    ),
    # Alternative explanations: Foreign interference
    safe_interference = NA,
    safe_interference01 = NA,
    keyword_interference_confident = NA,
    # Survey completion
    completed_pes = ifelse(!is.na(ces08_PES_INTDATE), 1, 0),
    completed_mbs = ifelse(!is.na(ces08_MBS_QLANG), 1, 0),
    pes_weight=NA
  )%>%
  # Select variables
  dplyr::select(year, satisfied, confidence, fairly, satisfied01, confidence01, fairly01,
                ideol, vote_choice, vote_lpc, vote_cpc, vote_winner,
                Atlantic,Quebec,Ontario,Prairies,BC, 
                feeling_winner, aff_pol_with_winner,
                feeling_lib, feeling_con, feeling_ndp, feeling_bq,
                feeling_green, feeling_ppc, spread_affect,
                aff_pol_libcon, aff_pol_ndp_winner, aff_pol_bq_winner,
                aff_pol_green_winner, aff_pol_ppc_winner, 
                interest, female, male, age_cat, age18_29, age30_44, age45_59, age60_,
                educ_cat, highschool, college, university, region,
                mail_distrust, mail_distrust01,
                satisf_voting, satisf_voting01, turnout,
                trust_pub_serv, trust_media, trust_fedgov, 
                safe_interference, safe_interference01, keyword_interference_confident,
                completed_pes, completed_mbs,
                ces08_NATWGT, pes_weight) %>% 
  # Rename weighting variable
  rename(cps_weight = ces08_NATWGT)
```

2011 election

```{r}
ces11 <- ces2011 %>% 
  mutate(
    # Election year
    year=2011,
    # Trust in election administration (full scale)
    satisfied = case_when(
      PES11_10==1 ~ 1,
      PES11_10==3 ~ 0.67,
      PES11_10==5 ~ 0.33,
      PES11_10==7 ~ 0,
      TRUE ~ NA_real_),
    confidence = case_when(
      MBS11_D2l==1 ~ 1,
      MBS11_D2l==2 ~ 0.67,
      MBS11_D2l==3 ~ 0.33,
      MBS11_D2l==4 ~ 0,
      TRUE~NA_real_),
    fairly = case_when(
      MBS11_J1==1 ~ 1,
      MBS11_J1==2 ~ 0.67,
      MBS11_J1==3 ~ 0.33,
      MBS11_J1==4 ~ 0,
      TRUE~NA_real_),
    # Trust in election administration (dummy)
    satisfied01 = ifelse(satisfied > 0.5, 1, 0),
    confidence01 = ifelse(confidence > 0.5, 1, 0),
    fairly01 = ifelse(fairly > 0.5, 1, 0),
    # Ideology and vote choice
    ideol = ifelse(!MBS11_K5 %in% c(0:10), NA, MBS11_K5),
    vote_choice = case_when(
      PES11_6 == 1 ~ "Liberal",
      PES11_6 == 2 ~ "Conservative",
      PES11_6 == 3 ~ "NDP",
      PES11_6 == 4 ~ "BQ",
      PES11_6 == 5 ~ "Green",
      TRUE ~ NA_character_),
    vote_lpc = ifelse(vote_choice == "Liberal", 1, 0),
    vote_cpc = ifelse(vote_choice == "Conservative", 2, 0),
    vote_ndp = ifelse(vote_choice == "NDP", 3, 0),
    vote_bq = ifelse(vote_choice == "BQ", 4, 0),
    vote_green = ifelse(vote_choice == "Green", 5, 0),
    vote_winner = case_when(
      PES11_6 == 2 ~ 1,
      PES11_6 %in% c(1,3,4,5) ~ 0,
      TRUE ~ NA_real_),
    # Affective polarization
    feeling_winner = ifelse(!CPS11_18 %in% c(0:100), NA, CPS11_18),
    feeling_lib = ifelse(!CPS11_19 %in% c(0:100), NA, CPS11_19),
    feeling_con = ifelse(!CPS11_18 %in% c(0:100), NA, CPS11_18),
    feeling_ndp = ifelse(!CPS11_20 %in% c(0:100), NA, CPS11_20),
    feeling_bq = ifelse(!CPS11_21 %in% c(0:100), NA, CPS11_21),
    feeling_green = ifelse(!CPS11_22 %in% c(0:100), NA, CPS11_22),
    feeling_ppc = NA,
    aff_pol_libcon = abs(feeling_lib-feeling_con),
    aff_pol_ndp_winner = abs(feeling_ndp-feeling_winner),
    aff_pol_bq_winner = abs(feeling_bq-feeling_winner),
    aff_pol_green_winner = abs(feeling_green-feeling_winner),
    aff_pol_ppc_winner = NA,
    aff_pol_with_winner = case_when(
      vote_choice == "Liberal" ~ aff_pol_libcon,
      vote_choice == "Conservative" ~ NA_real_,
      vote_choice == "NDP" ~ aff_pol_ndp_winner,
      vote_choice == "BQ" ~ aff_pol_bq_winner,
      vote_choice == "Green" ~ aff_pol_green_winner,
    ),
    # Affective polarization: Weighted spread of affects
    share_lib = 0.1891,
    share_con = 0.3962,
    share_ndp = 0.3063,
    share_bq = 0.0604,
    share_green = 0.0391,
    share_ppc = NA,
    weight_lib = feeling_lib*share_lib,
    weight_con = feeling_con*share_con,
    weight_ndp = feeling_ndp*share_ndp,
    weight_bq =  feeling_bq*share_bq,
    weight_green = feeling_green*share_green,
    weight_ppc =   NA,
    mean_affect = weight_lib+weight_con+weight_ndp+weight_bq+weight_green,
    distance_lib = (feeling_lib-mean_affect)^2,
    distance_con = (feeling_con-mean_affect)^2,
    distance_ndp = (feeling_ndp-mean_affect)^2,
    distance_bq = (feeling_bq-mean_affect)^2,
    distance_green = (feeling_green-mean_affect)^2,
    distance_ppc = NA,
    wt_sq_lib = distance_lib*share_lib,
    wt_sq_con = distance_con*share_con,
    wt_sq_ndp = distance_ndp*share_ndp,
    wt_sq_bq = distance_bq*share_bq,
    wt_sq_green = distance_green*share_green,
    wt_sq_ppc = NA,
    sum_polariz = wt_sq_lib+wt_sq_con+wt_sq_ndp+wt_sq_bq+wt_sq_green,
    spread_affect = sqrt(sum_polariz),
    # Socio-demographic characteristics
    interest  = ifelse(!PES11_60 %in% c(0:10), NA, PES11_60),
    female = ifelse(RGENDER11 == 1, 0, 1),
    male = ifelse(RGENDER11 == 5, 0, 1),
    age = ifelse(CPS11_78 != 9998 & CPS11_78 != 9999,  2011-CPS11_78, NA),
    age_cat = case_when(
      age >= 18 & age < 25 ~ 0,
      age >= 25 & age < 35 ~ 0.2,
      age >= 35 & age < 45 ~ 0.4,
      age >= 45 & age < 55 ~ 0.6,
      age >= 55 & age < 65 ~ 0.8,
      age >= 65 ~ 1,
      TRUE ~ NA_real_),
    age18_29 =ifelse(age >= 18 & age < 30, 1, 0),
    age30_44 =ifelse(age >= 30 & age < 45, 1, 0),
    age45_59 =ifelse(age >= 45 & age < 60, 1, 0),
    age60_ =ifelse(age >= 60, 1, 0),
    educ_cat = case_when(
      CPS11_79 %in% c(1:6) ~ 0, 
      CPS11_79 %in% c(7:8) ~ 0.5,
      CPS11_79 %in% c(9:11) ~ 1, 
      TRUE ~ NA_real_),
    highschool = ifelse(CPS11_79 %in% c(1:6), 1, 0),
    college = ifelse(CPS11_79 %in% c(7:8), 1, 0),
    university = ifelse(CPS11_79 %in% c(9:11), 1, 0),
    region = case_when(
      PROVINCE11 %in% c(10:13) ~ "Atlantic",
      PROVINCE11 ==24 ~ "Quebec",
      PROVINCE11 ==35 ~ "Ontario",
      PROVINCE11 %in% c(46:48) ~ "Prairies",
      PROVINCE11 ==59 ~ "British Columbia",
      TRUE ~ NA_character_),
    Atlantic=ifelse(region=="Atlantic", 1, 0),
    Quebec=ifelse(region=="Quebec", 1, 0),
    Ontario=ifelse(region=="Ontario", 1, 0),
    Prairies=ifelse(region=="Prairies", 1, 0),
    BC=ifelse(region=="British Columbia", 1, 0),
    # Trust in mail voting
    mail_distrust = NA,
    mail_distrust01 = NA,
    # Alternative explanations: Voting experiences
    satisf_voting = NA,
    satisf_voting01 = NA,
    turnout=NA, 
    # Alternative explanations: Generalized decline in trust
    trust_pub_serv = case_when(
      MBS11_D2e == 1 ~ 1,
      MBS11_D2e == 2 ~ 0.67,
      MBS11_D2e == 3 ~ 0.33,
      MBS11_D2e == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_media = case_when(
      MBS11_D2k == 1 ~ 1,
      MBS11_D2k == 2 ~ 0.67,
      MBS11_D2k == 3 ~ 0.33,
      MBS11_D2k == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_fedgov = case_when(
      MBS11_D2h == 1 ~ 1,
      MBS11_D2h == 2 ~ 0.67,
      MBS11_D2h == 3 ~ 0.33,
      MBS11_D2h == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    # Alternative explanations: Foreign interference
    safe_interference = NA,
    safe_interference01 = NA,
    keyword_interference_confident = NA,
    # Survey completion
    completed_pes = ifelse(!is.na(PES_INTDATE), 1, 0),
    completed_mbs = ifelse(!is.na(MBS11_LANG), 1, 0),
    pes_weight=NA
  )%>% 
  # Select variables
  dplyr::select(
    year, satisfied, confidence, fairly, satisfied01, confidence01, fairly01,
    ideol, vote_choice, vote_lpc, vote_cpc, vote_winner,
    Atlantic,Quebec,Ontario,Prairies,BC, 
    feeling_winner, aff_pol_with_winner,
    feeling_lib, feeling_con, feeling_ndp, feeling_bq,
    feeling_green, feeling_ppc, spread_affect,
    aff_pol_libcon, aff_pol_ndp_winner, aff_pol_bq_winner,
    aff_pol_green_winner, aff_pol_ppc_winner, 
    interest, female, male, age_cat, age18_29, age30_44, age45_59, age60_,
    educ_cat, highschool, college, university, region,
    mail_distrust, mail_distrust01,
    satisf_voting, satisf_voting01, turnout,
    trust_pub_serv, trust_media, trust_fedgov, 
    safe_interference, safe_interference01, keyword_interference_confident,
    completed_pes, completed_mbs,
    wgtsamp, pes_weight) %>%
  # Rename weighting variable
  rename(cps_weight = wgtsamp)
```

2015 election

```{r}
ces15 <- ces2015_phone %>% 
  mutate(
    # Election year
    year=2015,
    # Trust in election administration (full scale)
    satisfied = case_when(
      PES15_10j==1 ~ 1,
      PES15_10j==3 ~ 0.67,
      PES15_10j==5 ~ 0.33,
      PES15_10j==7 ~ 0,
      TRUE ~ NA_real_),
    confidence = case_when(
      MBS15_D2l==1 ~ 1,
      MBS15_D2l==2 ~ 0.67,
      MBS15_D2l==3 ~ 0.33,
      MBS15_D2l==4 ~ 0,
      TRUE ~ NA_real_),
    fairly = case_when(
      MBS15_J1==1 ~ 1,
      MBS15_J1==2 ~ 0.67,
      MBS15_J1==3 ~ 0.33,
      MBS15_J1==4 ~ 0,
      TRUE ~ NA_real_),
    # Trust in election administration (dummy)
    satisfied01 = ifelse(satisfied > 0.5, 1, 0),
    confidence01 = ifelse(confidence > 0.5, 1, 0),
    fairly01 = ifelse(fairly > 0.5, 1, 0),
    # Ideology and vote choice
    ideol = ifelse(!MBS15_K5 %in% c(0:10), NA, MBS15_K5),
    vote_choice = case_when(
      PES15_6 == 1 ~ "Liberal",
      PES15_6 == 2 ~ "Conservative",
      PES15_6 == 3 ~ "NDP",
      PES15_6 == 4 ~ "BQ",
      PES15_6 == 5 ~ "Green",
      TRUE ~ NA_character_),
    vote_lpc = ifelse(vote_choice == "Liberal", 1, 0),
    vote_cpc = ifelse(vote_choice == "Conservative", 2, 0),
    vote_ndp = ifelse(vote_choice == "NDP", 3, 0),
    vote_bq = ifelse(vote_choice == "BQ", 4, 0),
    vote_green = ifelse(vote_choice == "Green", 5, 0),
    vote_winner = case_when(
      PES15_6 == 1 ~ 1,
      PES15_6 %in% c(2,3,4,5) ~ 0,
      TRUE ~ NA_real_),
    # Affective polarization
    feeling_winner = ifelse(!CPS15_19 %in% c(0:100), NA, CPS15_19),
    feeling_lib = ifelse(!CPS15_19 %in% c(0:100), NA, CPS15_19),
    feeling_con = ifelse(!CPS15_18 %in% c(0:100), NA, CPS15_18),
    feeling_ndp = ifelse(!CPS15_20 %in% c(0:100), NA, CPS15_20),
    feeling_bq = ifelse(!CPS15_21 %in% c(0:100), NA, CPS15_21),
    feeling_green = ifelse(!CPS15_22 %in% c(0:100), NA, CPS15_22),
    feeling_ppc = NA,
    aff_pol_libcon = abs(feeling_lib-feeling_con),
    aff_pol_ndp_winner = abs(feeling_ndp-feeling_winner),
    aff_pol_bq_winner = abs(feeling_bq-feeling_winner),
    aff_pol_green_winner = abs(feeling_green-feeling_winner),
    aff_pol_ppc_winner = NA,
    aff_pol_with_winner = case_when(
      vote_choice == "Liberal" ~ NA_real_,
      vote_choice == "Conservative" ~ aff_pol_libcon,
      vote_choice == "NDP" ~ aff_pol_ndp_winner,
      vote_choice == "BQ" ~ aff_pol_bq_winner,
      vote_choice == "Green" ~ aff_pol_green_winner,
    ),
    # Affective polarization: Weighted spread of affects
    share_lib = 0.3947,
    share_con = 0.3191,
    share_ndp = 0.1972,
    share_bq = 0.0467,
    share_green = 0.0343,
    share_ppc = NA,
    weight_lib = feeling_lib*share_lib,
    weight_con = feeling_con*share_con,
    weight_ndp = feeling_ndp*share_ndp,
    weight_bq =  feeling_bq*share_bq,
    weight_green = feeling_green*share_green,
    weight_ppc =   NA,
    mean_affect = weight_lib+weight_con+weight_ndp+weight_bq+weight_green,
    distance_lib = (feeling_lib-mean_affect)^2,
    distance_con = (feeling_con-mean_affect)^2,
    distance_ndp = (feeling_ndp-mean_affect)^2,
    distance_bq = (feeling_bq-mean_affect)^2,
    distance_green = (feeling_green-mean_affect)^2,
    distance_ppc = NA,
    wt_sq_lib = distance_lib*share_lib,
    wt_sq_con = distance_con*share_con,
    wt_sq_ndp = distance_ndp*share_ndp,
    wt_sq_bq = distance_bq*share_bq,
    wt_sq_green = distance_green*share_green,
    wt_sq_ppc = NA,
    sum_polariz = wt_sq_lib+wt_sq_con+wt_sq_ndp+wt_sq_bq+wt_sq_green,
    spread_affect = sqrt(sum_polariz),
    # Socio-demographic characteristics
    interest  = ifelse(!PES15_60 %in% c(0:10), NA, PES15_60),
    female = ifelse(rgender == 1, 0, 1),
    male = ifelse(rgender == 5, 0, 1),
    age_cat = case_when(
      age_years >= 18 & age_years < 25 ~ 0,
      age_years >= 25 & age_years < 35 ~ 0.2,
      age_years >= 35 & age_years < 45 ~ 0.4,
      age_years >= 45 & age_years < 55 ~ 0.6,
      age_years >= 55 & age_years < 65 ~ 0.8,
      age_years >= 65 ~ 1,
      TRUE ~ NA_real_),
    age18_29 =ifelse(age_years >= 18 & age_years < 30, 1, 0),
    age30_44 =ifelse(age_years >= 30 & age_years < 45, 1, 0),
    age45_59 =ifelse(age_years >= 45 & age_years < 60, 1, 0),
    age60_ =ifelse(age_years >= 60, 1, 0),
    educ_cat = case_when(
      CPS15_79 %in% c(1:6) ~ 0, 
      CPS15_79 %in% c(7:8) ~ 0.5,
      CPS15_79 %in% c(9:11) ~ 1, 
      TRUE ~ NA_real_), 
    highschool = ifelse(CPS15_79 %in% c(1:6), 1, 0),
    college = ifelse(CPS15_79 %in% c(7:8), 1, 0),
    university = ifelse(CPS15_79 %in% c(9:11), 1, 0),
    region = case_when(
      CPS15_PROVINCE %in% c(10:13) ~ "Atlantic",
      CPS15_PROVINCE ==24 ~ "Quebec",
      CPS15_PROVINCE ==35 ~ "Ontario",
      CPS15_PROVINCE %in% c(46:48) ~ "Prairies",
      CPS15_PROVINCE ==59 ~ "British Columbia",
      TRUE ~ NA_character_),
    Atlantic=ifelse(region=="Atlantic", 1, 0),
    Quebec=ifelse(region=="Quebec", 1, 0),
    Ontario=ifelse(region=="Ontario", 1, 0),
    Prairies=ifelse(region=="Prairies", 1, 0),
    BC=ifelse(region=="British Columbia", 1, 0),
    # Trust in mail voting
    mail_distrust = NA,
    mail_distrust01 = NA,
    # Alternative explanations: Voting experiences
    satisf_voting = NA,
    satisf_voting01 = NA,
    turnout=NA,
    # Alternative explanations: Generalized decline in trust
    trust_pub_serv = case_when(
      MBS15_D2e == 1 ~ 1,
      MBS15_D2e == 2 ~ 0.67,
      MBS15_D2e == 3 ~ 0.33,
      MBS15_D2e == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_media = case_when(
      MBS15_D2k == 1 ~ 1,
      MBS15_D2k == 2 ~ 0.67,
      MBS15_D2k == 3 ~ 0.33,
      MBS15_D2k == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_fedgov = case_when(
      MBS15_D2h == 1 ~ 1,
      MBS15_D2h == 2 ~ 0.67,
      MBS15_D2h == 3 ~ 0.33,
      MBS15_D2h == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    # Alternative explanations: Foreign interference
    safe_interference = NA,
    safe_interference01 = NA,
    keyword_interference_confident = NA,
    # Survey completion
    completed_pes = ifelse(!is.na(PES15_INTDATE), 1, 0),
    completed_mbs = ifelse(!is.na(MBS15_LANG), 1, 0),
    pes_weight=NA
    )%>% 
  # Select variables
  dplyr::select(
    year, satisfied, confidence, fairly, satisfied01, confidence01, fairly01,
    ideol, vote_choice, vote_lpc, vote_cpc, vote_winner,
    Atlantic,Quebec,Ontario,Prairies,BC, 
    feeling_winner, aff_pol_with_winner,
    feeling_lib, feeling_con, feeling_ndp, feeling_bq,
    feeling_green, feeling_ppc, spread_affect,
    aff_pol_libcon, aff_pol_ndp_winner, aff_pol_bq_winner,
    aff_pol_green_winner, aff_pol_ppc_winner, 
    interest, female, male, age_cat, age18_29, age30_44, age45_59, age60_,
    educ_cat, highschool, college, university, region,
    mail_distrust, mail_distrust01,
    satisf_voting, satisf_voting01, turnout,
    trust_pub_serv, trust_media, trust_fedgov, 
    safe_interference, safe_interference01, keyword_interference_confident,
    completed_pes, completed_mbs,
    WeightTOsampBYPopul_count_Prov_H, pes_weight) %>% 
  # Rename weighting variable
  rename(cps_weight = WeightTOsampBYPopul_count_Prov_H)
```

2019 election

```{r}
ces19 <- ces2019_web %>% 
      mutate(
        # Election year
        year=2019,
        # Trust in election administration (full scale)
        satisfied = case_when(
          pes19_emb_satif==1 ~ 1,
          pes19_emb_satif==2 ~ 0.67,
          pes19_emb_satif==3 ~ 0.33,
          pes19_emb_satif==4 ~ 0,
          TRUE ~ NA_real_),
        confidence = case_when(
          pes19_conf_inst2_9==1 ~ 1,
          pes19_conf_inst2_9==2 ~ 0.67,
          pes19_conf_inst2_9==3 ~ 0.33,
          pes19_conf_inst2_9==4 ~ 0),
        fairly = case_when(
          pes19_emb8==1 ~ 1,
          pes19_emb8==2 ~ 0.67,
          pes19_emb8==3 ~ 0.33,
          pes19_emb8==4 ~ 0,
          TRUE ~ NA_real_),
        # Trust in election administration (dummy)
        fairly01 = ifelse(fairly > 0.5, 1, 0),
        satisfied01 = ifelse(satisfied > 0.5, 1, 0),
        confidence01 = ifelse(confidence > 0.5, 1, 0),
        # Ideology and vote choice
        ideol = ifelse(!cps19_lr_scale_bef_1 %in% c(0:10), NA, cps19_lr_scale_bef_1),
        vote_choice = case_when(
          pes19_votechoice2019 == 1 ~ "Liberal",
          pes19_votechoice2019 == 2 ~ "Conservative",
          pes19_votechoice2019 == 3 ~ "NDP",
          pes19_votechoice2019 == 4 ~ "BQ",
          pes19_votechoice2019 == 5 ~ "Green",
          pes19_votechoice2019 == 6 ~ "People's Party",
          TRUE ~ NA_character_),
        vote_lpc = ifelse(vote_choice == "Liberal", 1, 0),
        vote_cpc = ifelse(vote_choice == "Conservative", 2, 0),
        vote_ndp = ifelse(vote_choice == "NDP", 3, 0),
        vote_bq = ifelse(vote_choice == "BQ", 4, 0),
        vote_green = ifelse(vote_choice == "Green", 5, 0),
        vote_winner = case_when(
          pes19_votechoice2019 == 1 ~ 1,
          pes19_votechoice2019 %in% c(2,3,4,5) ~ 0,
          TRUE ~ NA_real_),
        # Affective polarization
        feeling_winner = ifelse(!cps19_party_rating_23 %in% c(0:100), NA, cps19_party_rating_23),
        feeling_lib = ifelse(!cps19_party_rating_23 %in% c(0:100), NA, cps19_party_rating_23),
        feeling_con = ifelse(!cps19_party_rating_24 %in% c(0:100), NA, cps19_party_rating_24),
        feeling_ndp = ifelse(!cps19_party_rating_25 %in% c(0:100), NA, cps19_party_rating_25),
        feeling_bq = ifelse(!cps19_party_rating_26 %in% c(0:100), NA, cps19_party_rating_26),
        feeling_green = ifelse(!cps19_party_rating_27 %in% c(0:100), NA, cps19_party_rating_27),
        feeling_ppc = ifelse(!cps19_party_rating_28 %in% c(0:100), NA, cps19_party_rating_28),
        aff_pol_libcon = abs(feeling_lib-feeling_con),
        aff_pol_ndp_winner = abs(feeling_ndp-feeling_winner),
        aff_pol_bq_winner = abs(feeling_bq-feeling_winner),
        aff_pol_green_winner = abs(feeling_green-feeling_winner),
        aff_pol_ppc_winner = abs(feeling_ppc-feeling_winner),
        aff_pol_with_winner = case_when(
          vote_choice == "Liberal" ~ NA_real_,
          vote_choice == "Conservative" ~ aff_pol_libcon,
          vote_choice == "NDP" ~ aff_pol_ndp_winner,
          vote_choice == "BQ" ~ aff_pol_bq_winner,
          vote_choice == "Green" ~ aff_pol_green_winner,
          vote_choice == "People's Party" ~ aff_pol_ppc_winner
        ),
        # Affective polarization: Weighted spread of affects
        share_lib = 0.3312,
        share_con = 0.3424,
        share_ndp = 0.1598,
        share_bq = 0.0763,
        share_green = 0.0655,
        share_ppc = 0.0162,
        weight_lib = feeling_lib*share_lib,
        weight_con = feeling_con*share_con,
        weight_ndp = feeling_ndp*share_ndp,
        weight_bq =  feeling_bq*share_bq,
        weight_green = feeling_green*share_green,
        weight_ppc =   feeling_ppc*share_ppc,
        mean_affect = weight_lib+weight_con+weight_ndp+weight_bq+weight_green,
        distance_lib = (feeling_lib-mean_affect)^2,
        distance_con = (feeling_con-mean_affect)^2,
        distance_ndp = (feeling_ndp-mean_affect)^2,
        distance_bq = (feeling_bq-mean_affect)^2,
        distance_green = (feeling_green-mean_affect)^2,
        distance_ppc = (feeling_ppc-mean_affect)^2,
        wt_sq_lib = distance_lib*share_lib,
        wt_sq_con = distance_con*share_con,
        wt_sq_ndp = distance_ndp*share_ndp,
        wt_sq_bq = distance_bq*share_bq,
        wt_sq_green = distance_green*share_green,
        wt_sq_ppc = distance_ppc*share_ppc,
        sum_polariz = wt_sq_lib+wt_sq_con+wt_sq_ndp+wt_sq_bq+wt_sq_green+wt_sq_ppc,
        spread_affect = sqrt(sum_polariz),
        # Socio-demographic characteristics
        interest  = ifelse(!pes19_interest_1 %in% c(0:10), NA, pes19_interest_1),
        female = case_when(
          cps19_gender == 1 ~ 0,
          cps19_gender == 2 ~ 1,
          TRUE ~ NA_real_),
        male = case_when(
          cps19_gender == 1 ~ 1,
          cps19_gender == 2 ~ 0,
          TRUE ~ NA_real_),
        age_cat = case_when(
          cps19_age >= 18 & cps19_age < 25 ~ 0,
          cps19_age >= 25 & cps19_age < 35 ~ 0.2,
          cps19_age >= 35 & cps19_age < 45 ~ 0.4,
          cps19_age >= 45 & cps19_age < 55 ~ 0.6,
          cps19_age >= 55 & cps19_age < 65 ~ 0.8,
          cps19_age >= 65 ~ 1, 
          TRUE ~ NA_real_),
        age18_29 =ifelse(cps19_age >= 18 & cps19_age < 30, 1, 0),
        age30_44 =ifelse(cps19_age >= 30 & cps19_age < 45, 1, 0),
        age45_59 =ifelse(cps19_age >= 45 & cps19_age < 60, 1, 0),
        age60_ =ifelse(cps19_age >= 60, 1, 0),
        educ_cat = case_when(
          cps19_education %in% c(1:6) ~ 0, 
          cps19_education %in% c(7:8) ~ 0.5,
          cps19_education %in% c(9:11) ~ 1, 
          TRUE ~ NA_real_), 
        highschool = ifelse(cps19_education %in% c(1:6), 1, 0),
        college = ifelse(cps19_education %in% c(7:8), 1, 0),
        university = ifelse(cps19_education %in% c(9:11), 1, 0),
        region = case_when(
          cps19_province %in% c(17, 18, 20, 23) ~ "Atlantic",
          cps19_province ==24 ~ "Quebec",
          cps19_province ==22 ~ "Ontario",
          cps19_province %in% c(14, 16, 25) ~ "Prairies",
          cps19_province ==15 ~ "British Columbia",
          TRUE ~ NA_character_),
        Atlantic=ifelse(region=="Atlantic", 1, 0),
        Quebec=ifelse(region=="Quebec", 1, 0),
        Ontario=ifelse(region=="Ontario", 1, 0),
        Prairies=ifelse(region=="Prairies", 1, 0),
        BC=ifelse(region=="British Columbia", 1, 0),
        # Trust in mail voting
        mail_distrust = NA,
        mail_distrust01 = NA,
        turnout = NA,
        # Alternative explanations: Voting experiences
        satisf_voting = NA,
        satisf_voting01 = NA,
        # Alternative explanations: Generalized decline in trust
        trust_pub_serv = case_when(
          pes19_conf_inst2_7 == 1 ~ 1,
          pes19_conf_inst2_7 == 2 ~ 0.67,
          pes19_conf_inst2_7 == 3 ~ 0.33,
          pes19_conf_inst2_7 == 4 ~ 0,
          TRUE ~ NA_real_
        ),
        trust_media = case_when(
          pes19_conf_inst1_3 == 1 ~ 1,
          pes19_conf_inst1_3 == 2 ~ 0.67,
          pes19_conf_inst1_3 == 3 ~ 0.33,
          pes19_conf_inst1_3 == 4 ~ 0,
          TRUE ~ NA_real_
        ),
        trust_fedgov = case_when(
          pes19_conf_inst1_1 == 1 ~ 1,
          pes19_conf_inst1_1 == 2 ~ 0.67,
          pes19_conf_inst1_1 == 3 ~ 0.33,
          pes19_conf_inst1_1 == 4 ~ 0,
          TRUE ~ NA_real_
        ),
        # Alternative explanations: Foreign interference
        safe_interference = case_when(
          pes19_foreign == 1 ~ 1,
          pes19_foreign == 2 ~ 0.67,
          pes19_foreign == 3 ~ 0.33,
          pes19_foreign == 4 ~ 0,
          TRUE ~ NA_real_
        ),
        safe_interference01 = case_when(
          pes19_foreign == 1 ~ 1,
          pes19_foreign == 2 ~ 1,
          pes19_foreign == 3 ~ 0,
          pes19_foreign == 4 ~ 0,
          pes19_foreign == 5 ~ 0,
          TRUE ~ NA_real_
        ),
        keyword_interference_confident = ifelse(confidence_institutions_word=="confident", 1, 0),
        # Survey completion
        completed_pes = ifelse(!is.na(pes19_EndDate), 1, 0),
        completed_mbs = NA,
        pes_weight=pes19_weight_general_all
      )%>% 
  # Select variables
  dplyr::select(
    year, satisfied, confidence, fairly, satisfied01, confidence01, fairly01,
    ideol, vote_choice, vote_lpc, vote_cpc, vote_winner,
    Atlantic,Quebec,Ontario,Prairies,BC, 
    feeling_winner, aff_pol_with_winner,
    feeling_lib, feeling_con, feeling_ndp, feeling_bq,
    feeling_green, feeling_ppc, spread_affect,
    aff_pol_libcon, aff_pol_ndp_winner, aff_pol_bq_winner,
    aff_pol_green_winner, aff_pol_ppc_winner, 
    interest, female, male, age_cat, age18_29, age30_44, age45_59, age60_,
    educ_cat, highschool, college, university, region,
    mail_distrust, mail_distrust01,
    satisf_voting, satisf_voting01, turnout,
    trust_pub_serv, trust_media, trust_fedgov, 
    safe_interference, safe_interference01, keyword_interference_confident,
    completed_pes, completed_mbs,
    cps19_weight_general_all, pes_weight) %>% 
  # Rename weighting variable
  rename(cps_weight = cps19_weight_general_all)
```

2021 election

```{r}
ces21 <- ces2021 %>% 
  mutate(
    # Election year
    year=2021,
    # Trust in election administration (full scale)
    satisfied = case_when(
      pes21_emb_satif==1 ~ 1,
      pes21_emb_satif==2 ~ 0.67,
      pes21_emb_satif==3 ~ 0.33,
      pes21_emb_satif==4 ~ 0,
      TRUE ~ NA_real_),  
    confidence = case_when(
      pes21_conf_inst1_4==1 ~ 1,
      pes21_conf_inst1_4==2 ~ 0.67,
      pes21_conf_inst1_4==3 ~ 0.33,
      pes21_conf_inst1_4==4 ~ 0),
    fairly = case_when(
      pes21_emb8==1 ~ 1,
      pes21_emb8==2 ~ 0.67,
      pes21_emb8==3 ~ 0.33,
      pes21_emb8==4 ~ 0,
      TRUE ~ NA_real_),
    # Trust in election administration (dummy)
    satisfied01 = ifelse(satisfied > 0.5, 1, 0),
    confidence01 = ifelse(confidence > 0.5, 1, 0),
    fairly01 = ifelse(fairly > 0.5, 1, 0),
    # Ideology and vote choice
    ideol = ifelse(!cps21_lr_scale_bef_1 %in% c(0:10), NA, cps21_lr_scale_bef_1),
    vote_choice = case_when(
      pes21_votechoice2021 == 1 ~ "Liberal",
      pes21_votechoice2021 == 2 ~ "Conservative",
      pes21_votechoice2021 == 3 ~ "NDP",
      pes21_votechoice2021 == 4 ~ "BQ",
      pes21_votechoice2021 == 5 ~ "Green",
      pes21_votechoice2021 == 6 ~ "People's Party",
      TRUE ~ NA_character_),
    vote_lpc = ifelse(vote_choice == "Liberal", 1, 0),
    vote_cpc = ifelse(vote_choice == "Conservative", 2, 0),
    vote_ndp = ifelse(vote_choice == "NDP", 3, 0),
    vote_bq = ifelse(vote_choice == "BQ", 4, 0),
    vote_green = ifelse(vote_choice == "Green", 5, 0),
    vote_winner = case_when(
      pes21_votechoice2021 == 1 ~ 1,
      pes21_votechoice2021 %in% c(2,3,4,5) ~ 0,
      TRUE ~ NA_real_),
    # Affective polarization
    feeling_winner = ifelse(!cps21_party_rating_23 %in% c(0:100), NA, cps21_party_rating_23),
    feeling_lib = ifelse(!cps21_party_rating_23 %in% c(0:100), NA, cps21_party_rating_23),
    feeling_con = ifelse(!cps21_party_rating_24 %in% c(0:100), NA, cps21_party_rating_24),
    feeling_ndp = ifelse(!cps21_party_rating_25 %in% c(0:100), NA, cps21_party_rating_25),
    feeling_bq = ifelse(!cps21_party_rating_26 %in% c(0:100), NA, cps21_party_rating_26),
    feeling_green = ifelse(!cps21_party_rating_27 %in% c(0:100), NA, cps21_party_rating_27),
    feeling_ppc = ifelse(!cps21_party_rating_29 %in% c(0:100), NA, cps21_party_rating_29),
    aff_pol_libcon = abs(feeling_lib-feeling_con),
    aff_pol_ndp_winner = abs(feeling_ndp-feeling_winner),
    aff_pol_bq_winner = abs(feeling_bq-feeling_winner),
    aff_pol_green_winner = abs(feeling_green-feeling_winner),
    aff_pol_ppc_winner = abs(feeling_ppc-feeling_winner),
    aff_pol_with_winner = case_when(
      vote_choice == "Liberal" ~ NA_real_,
      vote_choice == "Conservative" ~ aff_pol_libcon,
      vote_choice == "NDP" ~ aff_pol_ndp_winner,
      vote_choice == "BQ" ~ aff_pol_bq_winner,
      vote_choice == "Green" ~ aff_pol_green_winner,
      vote_choice == "People's Party" ~ aff_pol_ppc_winner,
    ),
    # Affective polarization: Weighted spread of affects
    share_lib = 0.3262,
    share_con = 0.3374,
    share_ndp = 0.1782,
    share_bq = 0.0764,
    share_green = 0.0233,
    share_ppc = 0.0494,
    weight_lib = feeling_lib*share_lib,
    weight_con = feeling_con*share_con,
    weight_ndp = feeling_ndp*share_ndp,
    weight_bq =  feeling_bq*share_bq,
    weight_green = feeling_green*share_green,
    weight_ppc =   feeling_ppc*share_ppc,
    mean_affect = weight_lib+weight_con+weight_ndp+weight_bq+weight_green,
    distance_lib = (feeling_lib-mean_affect)^2,
    distance_con = (feeling_con-mean_affect)^2,
    distance_ndp = (feeling_ndp-mean_affect)^2,
    distance_bq = (feeling_bq-mean_affect)^2,
    distance_green = (feeling_green-mean_affect)^2,
    distance_ppc = (feeling_ppc-mean_affect)^2,
    wt_sq_lib = distance_lib*share_lib,
    wt_sq_con = distance_con*share_con,
    wt_sq_ndp = distance_ndp*share_ndp,
    wt_sq_bq = distance_bq*share_bq,
    wt_sq_green = distance_green*share_green,
    wt_sq_ppc = distance_ppc*share_ppc,
    sum_polariz = wt_sq_lib+wt_sq_con+wt_sq_ndp+wt_sq_bq+wt_sq_green+wt_sq_ppc,
    spread_affect = sqrt(sum_polariz),
    # Socio-demographic characteristics
    interest  = ifelse(!cps21_interest_gen_1 %in% c(0:10), NA, cps21_interest_gen_1),
    female = case_when(
      cps21_genderid == 1 ~ 0,
      cps21_genderid == 2 ~ 1,
      TRUE ~ NA_real_),
    male = case_when(
      cps21_genderid == 1 ~ 1,
      cps21_genderid == 2 ~ 0,
      TRUE ~ NA_real_),
    age_cat = case_when(
      cps21_age >= 18 & cps21_age < 25 ~ 0,
      cps21_age >= 25 & cps21_age < 35 ~ 0.2,
      cps21_age >= 35 & cps21_age < 45 ~ 0.4,
      cps21_age >= 45 & cps21_age < 55 ~ 0.6,
      cps21_age >= 55 & cps21_age < 65 ~ 0.8,
      cps21_age >= 65 ~ 1, 
      TRUE ~ NA_real_),
    age18_29 =ifelse(cps21_age >= 18 & cps21_age < 30, 1, 0),
    age30_44 =ifelse(cps21_age >= 30 & cps21_age < 45, 1, 0),
    age45_59 =ifelse(cps21_age >= 45 & cps21_age < 60, 1, 0),
    age60_ =ifelse(cps21_age >= 60, 1, 0),
    educ_cat = case_when(
      cps21_education %in% c(1:6) ~ 0, 
      cps21_education %in% c(7:8) ~ 0.5,
      cps21_education %in% c(9:11) ~ 1, 
      TRUE ~ NA_real_),
    highschool = ifelse(cps21_education %in% c(1:6), 1, 0),
    college = ifelse(cps21_education %in% c(7:8), 1, 0),
    university = ifelse(cps21_education %in% c(9:11), 1, 0),
    region = case_when(
      provcode %in% c(10:13) ~ "Atlantic",
      provcode ==24 ~ "Quebec",
      provcode ==35 ~ "Ontario",
      provcode %in% c(46:48) ~ "Prairies",
      provcode ==59 ~ "British Columbia",
      TRUE ~ NA_character_),
    Atlantic=ifelse(region=="Atlantic", 1, 0),
    Quebec=ifelse(region=="Quebec", 1, 0),
    Ontario=ifelse(region=="Ontario", 1, 0),
    Prairies=ifelse(region=="Prairies", 1, 0),
    BC=ifelse(region=="British Columbia", 1, 0),
    # Trust in mail voting
    mail_distrust = case_when(
      cps21_pos_mailtrust == 1 ~ 1,
      cps21_pos_mailtrust == 2 ~ 0.75,
      cps21_pos_mailtrust == 3 ~ 0.5,
      cps21_pos_mailtrust == 4 ~ 0.25,
      cps21_pos_mailtrust == 5 ~ 0,
      cps21_pos_mailtrust == 6 ~ 0.5
    ),
    mail_distrust01 = case_when(
      cps21_pos_mailtrust %in% c(3,4,5,6) ~ 0,
      cps21_pos_mailtrust %in% c(1,2) ~ 1,
    ),
    # Alternative explanations: Voting experiences
    satisf_voting = case_when(
      pes21_embsatisfy == 1 ~ 1,
      pes21_embsatisfy == 2 ~ 0.67,
      pes21_embsatisfy == 3 ~ 0.33,
      pes21_embsatisfy == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    satisf_voting01 = case_when(
      pes21_embsatisfy %in% c(1,2) ~ 1, 
      pes21_embsatisfy %in% c(3,4,5) ~ 0,
      TRUE ~ NA_real_),
    turnout = pes21_turnout2021,
    # Alternative explanations: Generalized decline in trust
    trust_pub_serv = case_when(
      pes21_conf_inst2_5 == 1 ~ 1,
      pes21_conf_inst2_5 == 2 ~ 0.67,
      pes21_conf_inst2_5 == 3 ~ 0.33,
      pes21_conf_inst2_5 == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_media = case_when(
      pes21_conf_inst1_3 == 1 ~ 1,
      pes21_conf_inst1_3 == 2 ~ 0.67,
      pes21_conf_inst1_3 == 3 ~ 0.33,
      pes21_conf_inst1_3 == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    trust_fedgov = case_when(
      pes21_conf_inst1_1 == 1 ~ 1,
      pes21_conf_inst1_1 == 2 ~ 0.67,
      pes21_conf_inst1_1 == 3 ~ 0.33,
      pes21_conf_inst1_1 == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    # Alternative explanations: Foreign interference
    safe_interference = case_when(
      pes21_foreign == 1 ~ 1,
      pes21_foreign == 2 ~ 0.67,
      pes21_foreign == 3 ~ 0.33,
      pes21_foreign == 4 ~ 0,
      TRUE ~ NA_real_
    ),
    safe_interference01 = case_when(
      pes21_foreign == 1 ~ 1,
      pes21_foreign == 2 ~ 1,
      pes21_foreign == 3 ~ 0,
      pes21_foreign == 4 ~ 0,
      pes21_foreign == 5 ~ 0,
      TRUE ~ NA_real_
    ),
    keyword_interference_confident = c(1),
    # Survey completion
    completed_pes = ifelse(!is.na(pes21_EndDate), 1, 0),
    completed_mbs = NA,
    pes_weight = pes21_weight_general_all
  ) %>% 
  # Select variables
  dplyr::select(
    year, satisfied, confidence, fairly, satisfied01, confidence01, fairly01,
    ideol, vote_choice, vote_lpc, vote_cpc, vote_winner,
    Atlantic,Quebec,Ontario,Prairies,BC, 
    feeling_winner, aff_pol_with_winner,
    feeling_lib, feeling_con, feeling_ndp, feeling_bq,
    feeling_green, feeling_ppc, spread_affect,
    aff_pol_libcon, aff_pol_ndp_winner, aff_pol_bq_winner,
    aff_pol_green_winner, aff_pol_ppc_winner, 
    interest, female, male, age_cat, age18_29, age30_44, age45_59, age60_,
    educ_cat, highschool, college, university, region,
    mail_distrust, mail_distrust01,
    satisf_voting, satisf_voting01, turnout,
    trust_pub_serv, trust_media, trust_fedgov, 
    safe_interference, safe_interference01, keyword_interference_confident,
    completed_pes, completed_mbs,
    cps21_weight_general_all, pes_weight) %>% 
  # Rename weighting variable
  rename(cps_weight = cps21_weight_general_all)
```

## Combine all years + recode variables

```{r}
dat <- rbind(ces08, ces11, ces15, ces19, ces21) %>% 
  mutate(
    # Factor variable for Year
    year = factor(year), 
    Year = year,
    # Categorical measure of ideology
    ideol_cat = case_when(
      ideol <5 ~ "Left",
      ideol == 5 ~ "Centre",
      ideol > 5 ~ "Right",
      TRUE ~ NA_character_
    ),
    # Categorical measure of ideology (v2)
    ideol2 = case_when(
      ideol %in% c(0:3) ~ "Left (0-3)",
      ideol %in% c(4:6) ~ "Moderate (4-6)",
      ideol %in% c(7:10) ~ "Right (7-10)"),
    # Factor variable for vote_choice
    vote_choice = factor(vote_choice, 
                         levels = c("Liberal", "Conservative", "NDP", "BQ", "Green", "People's Party")),
    # Party family
    party_family = case_when(
      vote_choice %in% c("Liberal", "NDP", "Green") ~ "Left-wing parties",
      vote_choice %in% c("Conservative", "People's Party") ~ "Right-wing parties"),
    # Dichotomize trust in institutions
    trust_pub_serv01 = ifelse(trust_pub_serv > 0.5, 1, 0),
    trust_media01 = ifelse(trust_media > 0.5, 1, 0),
    trust_fedgov01 = ifelse(trust_fedgov > 0.5, 1, 0),
    # Put election trust variables on 4-point scales
    satisfied_4point = case_when(
      satisfied == 0 ~ 1,
      satisfied == 0.33 ~ 2,
      satisfied == 0.67 ~ 3,
      satisfied == 1 ~ 4
    ),
    confidence_4point = case_when(
      confidence == 0 ~ 1,
      confidence == 0.33 ~ 2,
      confidence == 0.67 ~ 3,
      confidence == 1 ~ 4
    ),
    fairly_4point = case_when(
      fairly == 0 ~ 1,
      fairly == 0.33 ~ 2,
      fairly == 0.67 ~ 3,
      fairly == 1 ~ 4
    ),
    # Put affective polarization measures on 0-1 scales
    feeling_winner01 = feeling_winner/100,
    aff_pol_libcon01 = aff_pol_libcon/100,
    aff_pol_with_winner01 = aff_pol_with_winner/100
  )

# Survey design
dat_nona <- filter(dat, !is.na(cps_weight))
design <- svydesign(ids=~1, data=dat_nona, weights = dat_nona$cps_weight)
```

## Figure 1: Trust in election administration over time

```{r}
# Calculate % of respondents who have confidence in Elections Canada by year
wt_confidence <- svyby(~confidence01, ~factor(year), design, svymean, na.rm = T)%>% 
  mutate(Variable = "Confidence") %>% 
  rename(value = confidence01,
         year = `factor(year)`)

# Calculate % of respondents who believe the election was administered fairly by year
wt_fairly <- svyby(~fairly01, ~factor(year), design, svymean, na.rm = T) %>% 
  mutate(Variable = "Fairly") %>% 
  rename(value = fairly01,
         year = `factor(year)`)

# Calculate % of respondents who are satisfied by year
wt_satisfied <- svyby(~satisfied01, ~factor(year), design, svymean, na.rm = T)%>% 
  mutate(Variable = "Satisfied") %>% 
  rename(value = satisfied01,
         year = `factor(year)`)

# Merge responses
wt_time <- rbind(wt_confidence, wt_fairly, wt_satisfied) %>% 
  # Put year variable into numeric format
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Calculate confidence intervals
  lower=value-1.96*se, upper=value+1.96*se, 
  # Specify order of trust variables
  Variable = factor(Variable, levels = c("Confidence", "Fairly", "Satisfied")))

# Create figure
fig_1 <- ggplot(wt_time, aes(x = year_num, y = value))+
  geom_point(aes(col = Variable, shape = Variable), size = 2.5)+
  geom_line(aes(col = Variable, group = Variable))+
  geom_errorbar(aes(ymin = value-1.96*se, ymax = value+1.96*se, col = Variable, group = Variable), width = 0, size=0.8)+
  scale_y_continuous(limits = c(0, 0.99), breaks = c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     labels = percent_format(accuracy = 1))+
  scale_x_continuous(limits = c(2008, 2021), breaks = c(2008:2021),
                     labels = c("2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017",
                                "2018", "2019", "2020", "2021"))+
  scale_color_manual(values = c("red3", "blue3", "green4"), 
                     labels = c("Confidence in\nElections Canada", "Election was\nadministered fairly", "Satisfied with the way Elections\n Canada runs elections"))+
  scale_shape_manual(values=c(15:17), 
                     labels = c("Confidence in\nElections Canada", "Election was\nadministered fairly", "Satisfied with the way Elections\n Canada runs elections"))+
  labs(x = "Year",
       y = "Percentage of Canadians", 
       color="",
       shape="")+
  theme_minimal()+
  theme(legend.position = "top",
        panel.grid.minor.x = element_blank())

# Save figure
ggsave(fig_1, file="./Figures/Figure_1_time_ovrl.png", height = 4.5, dpi=600, bg = "white")
```

## Figure 2: Trust in election administration over time by ideology and vote choice

```{r}
# Perceptions of election administration by ideology
confidence_ideol <- summarize_weighted(data = dat, dv = "confidence01", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Confidence")

fairly_ideol <- summarize_weighted(data = dat, dv = "fairly01", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Fairly")

satisfied_ideol <- summarize_weighted(data = dat, dv = "satisfied01", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Satisfied")

# Merge outputs
time_ideol <- rbind(satisfied_ideol, confidence_ideol, fairly_ideol) %>% 
  # Put year variable in numeric formmat
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Specify order of ideology categories
  ideol2 = factor(ideol2, levels = c("Left (0-3)", "Moderate (4-6)", "Right (7-10)")))

# Create figure (ideology panel)
fig_2a <- ggplot(time_ideol, aes(x=year_num, y = value, col = ideol2, shape=ideol2))+
  geom_point(size=2, position=position_dodge(0.7))+
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, alpha=0.3, position=position_dodge(0.7))+
  geom_line(aes(group=ideol2), position=position_dodge(0.7))+
  facet_wrap(~var)+
  scale_y_continuous(limits = c(0.3, 1), breaks = c(0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     labels = percent_format(accuracy = 1))+
  scale_x_continuous(limits = c(2007.5, 2021.5), breaks = c(2008:2021),
                     labels = c("08", "09", "10", "11", "12", "13", "14", "15", "16", "17",
                                "18", "19", "20", "21"))+
  scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values=c(2,1,0))+
  labs(x = "Year",
       y = "Percentage of supporters", 
       color="",
       shape="",
       title="Ideology")+
  theme_minimal()+
  theme(legend.position = "right",
        plot.title = element_text(size=12),
        axis.title.x=element_blank(),
        strip.text=element_text(size=11),
        panel.grid.minor = element_blank())

# Perceptions of election administration by vote choice
confidence_vote <- summarize_weighted(data = dat, dv = "confidence01", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Confidence")

fairly_vote <- summarize_weighted(data = dat, dv = "fairly01", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Fairly")

satisfied_vote <- summarize_weighted(data = dat, dv = "satisfied01", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Satisfied")

# Merge outputs
time_vote <- rbind(satisfied_vote, confidence_vote, fairly_vote) %>% 
  # Put year variable into numeric format
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Identify governing parties
  alpha=ifelse(vote_choice %in% c("Liberal", "Conservative"), 1, 0))

# Create figure (vote choice panel)

# Define the base colors
base_colors <- c("red3", "blue3", "orange", "cyan3", "green4", "purple")

# Adjust transparency for specific colors (orange, cyan3, green4, purple)
new_colors <- c(base_colors[1:2], 
                adjustcolor(base_colors[3], alpha.f = 0.35), 
                adjustcolor(base_colors[4], alpha.f = 0.35), 
                adjustcolor(base_colors[5], alpha.f = 0.35), 
                adjustcolor(base_colors[6], alpha.f = 0.35))

# Create figure
fig_2b <- ggplot(time_vote, aes(x=year_num, y=value, col=vote_choice, shape=vote_choice)) +
  geom_point(size=2, position=position_dodge(0.7)) +
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, position=position_dodge(0.7)) +
  geom_line(aes(group=vote_choice), position=position_dodge(0.7)) +
  facet_wrap(~var) +
  scale_y_continuous(limits=c(0.25, 1), breaks=seq(0.3, 1, by=0.1), labels=percent_format(accuracy=1)) +
  scale_x_continuous(limits=c(2007.5, 2021.5), breaks=2008:2021, labels=as.character(2008:2021 %% 100)) +
  scale_color_manual(values=new_colors,
                     labels=c("Liberal", "Conservative", "New Democrat", "Bloc Québécois", "Green", "People's Party")) +
  scale_shape_manual(values=c(16, 15, 17, 18, 20, 8),
                     labels=c("Liberal", "Conservative", "New Democrat", "Bloc Québécois", "Green", "People's Party")) +
  labs(x="Year",
       y="Percentage of supporters", 
       color="Vote Choice",
       title="Vote choice", 
       shape="Vote Choice",
       alpha="Governing party") +
  theme_minimal() +
  theme(legend.position="right",
        plot.title=element_text(size=12),
        strip.text=element_blank(),
        panel.grid.minor=element_blank())

# Combine two panels
fig_2 <- fig_2a/fig_2b

# Save figure
ggsave(fig_2, file="./Figures/Figure_2_over_time_party_ideol.png", height=7, width=10, dpi=600, bg = "white")
```

## Figure 3: Affective polarization over time

```{r}
# Average feelings towards each party by vote choice
feelings_lib <- summarize_weighted(data = dat, dv = "feeling_lib", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Liberals")

feelings_con <- summarize_weighted(data = dat, dv = "feeling_con", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Conservatives")

feelings_ndp <- summarize_weighted(data = dat, dv = "feeling_ndp", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "NDP")

feelings_bq <- summarize_weighted(data = dat, dv = "feeling_bq", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Bloc Quebecois (Quebec)")

feelings_green <- summarize_weighted(data = dat, dv = "feeling_green", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Green")

feelings_ppc <- summarize_weighted(data = dat, dv = "feeling_ppc", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "People's Party")

# Merge outputs
fig_3 <- rbind(feelings_lib, feelings_con, feelings_ndp, feelings_bq, feelings_green, feelings_ppc) %>% 
  # Specify order of parties
  mutate(var = factor(var, levels=c("Liberals", "Conservatives", "NDP", "Bloc Quebecois (Quebec)", "Green", "People's Party")),
         # Put year variable into numeric format
         year_num = case_when(
           year=="2008" ~ 2008,
           year=="2011" ~ 2011,
           year=="2015" ~ 2015,
           year=="2019" ~ 2019,
           year=="2021" ~ 2021
         )) %>% 
  # Create figure
  ggplot(aes(x=year_num, y=value, col=vote_choice, shape=vote_choice))+
  geom_line(aes(group=vote_choice), position=position_dodge(0.7))+
  geom_point(position=position_dodge(0.7), size=1.75)+
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, position=position_dodge(0.7), size = 0.6, alpha=0.3)+
  geom_hline(yintercept=50, linetype="dashed", col="grey")+
  facet_wrap(~var)+
  scale_x_continuous(breaks=c(2009, 2012, 2015, 2018, 2021))+
  scale_y_continuous(limits=c(10,90), breaks=c(seq(10,90, by=10)))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"),
                     labels=c("Liberals", "Conservatives", "NDP", "Bloc Québécois", "Green", "People's Party"))+
  scale_shape_manual(values=c(16, 15, 17, 18, 20, 8),
                     labels=c("Liberals", "Conservatives", "NDP", "Bloc Québécois", "Green", "People's Party")) +
  labs(x="Year",
       y="Feelings (0-100)",
       col="Vote", 
       shape="Vote")+
  theme_minimal()+
  theme(legend.position="top",
        panel.grid.minor.y = element_blank())

# Save figure
ggsave(fig_3, file="./Figures/Figure_3_affective_polarization.png", height=6, width=7, dpi=600, bg = "white")
```

## Figure 4: Effect of feelings towards the winning party and gap in feelings between their own party and the winning party

```{r}
# Specify control variables
basic_controls <- "vote_choice + interest + female + age_cat + educ_cat + region" 

# Function to run lm_robust with common arguments
run_model <- function(outcome, predictor, data, controls, weight_var) {
  formula_str <- paste0(outcome, " ~ ", predictor, "*Year + ", controls)
  lm_robust(data = data, weights = !!sym(weight_var), se_type = "HC2", formula = formula(formula_str))
}

outcomes <- c("fairly_4point", "confidence_4point", "satisfied_4point")
predictors <- c("feeling_winner01", "aff_pol_with_winner01")

# Create empty list to store models
models <- list()

for (pred in predictors) {
  for (outcome in outcomes) {
    model_name <- paste0(outcome, "_", pred)
    models[[model_name]] <- run_model(outcome, pred, dat, basic_controls, "cps_weight")
  }
}

fairly_feel_win <- lm_robust(data=dat, weights=cps_weight,  se_type = "HC2",
   formula = formula(paste0("fairly_4point ~ feeling_winner01*Year +", basic_controls)))

# Function to create figures
plot_aff_pol <- function(model, predictor, y_limits, y_breaks, y_label="", x_label="", 
                         draw_error=FALSE, theme_overrides=list()) {
  
  df <- plot_slopes(model, variables = predictor, condition = "Year", draw = !draw_error)
  
  p <- if(draw_error) {
    ggplot(df, aes(x=Year, y=estimate, ymin=conf.low, ymax=conf.high)) +
      geom_point(size=2.5) +
      geom_errorbar(width=0)
  } else {
    df + geom_point(size=2.5)
  }
  
  p <- p + 
    geom_hline(yintercept=0, linetype=2) +
    scale_y_continuous(limits=y_limits, breaks=y_breaks) +
    labs(x=x_label, y=y_label) +
    theme_minimal() +
    theme(plot.title = element_text(size=12, hjust=0.5),
          axis.text = element_text(size=10.5)) # default text
  
  # Apply any theme overrides passed as a list
  if(length(theme_overrides) > 0) {
    p <- p + do.call(theme, theme_overrides)
  }
  
  return(p)
}


# Generate figures
# For feeling_winner01
plots_feeling <- lapply(outcomes, function(outcome) {
  plot_aff_pol(models[[paste0(outcome, "_feeling_winner01")]], 
               predictor = "feeling_winner01",
               y_limits = c(-0.1, 1), 
               y_breaks = seq(0, 1, 0.25),
               y_label = "Marginal effect")
})

# For aff_pol_with_winner01
plots_gap <- lapply(outcomes, function(outcome) {
  plot_aff_pol(models[[paste0(outcome, "_aff_pol_with_winner01")]], 
               predictor = "aff_pol_with_winner01",
               y_limits = c(-0.75, 0.3), 
               y_breaks = c(-0.75, -0.5, -0.25, 0, 0.25),
               y_label = "Marginal effect",
               draw_error = TRUE)
})

# Fix axis labels
plots_feeling <- list(
  plot_aff_pol(models[["confidence_4point_feeling_winner01"]], "feeling_winner01",
               y_limits=c(-0.1,1), y_breaks=seq(0,1,0.25), y_label="Marginal effect",
               theme_overrides=list(axis.text.x=element_blank(),axis.title.x=element_blank())) +
    ggtitle("On confidence"),

  plot_aff_pol(models[["fairly_4point_feeling_winner01"]], "feeling_winner01",
               y_limits=c(-0.1,1), y_breaks=seq(0,1,0.25),
               theme_overrides=list(axis.text=element_blank(), axis.title=element_blank())) +
    ggtitle("On perceived fairness"),

  plot_aff_pol(models[["satisfied_4point_feeling_winner01"]], "feeling_winner01",
               y_limits=c(-0.1,1), y_breaks=seq(0,1,0.25),
               theme_overrides=list(axis.text=element_blank(), axis.title=element_blank())) +
    ggtitle("On satisfaction")
)

plots_gap <- list(
  plot_aff_pol(models[["confidence_4point_aff_pol_with_winner01"]], "aff_pol_with_winner01",
               y_limits = c(-0.75, 0.3), y_breaks = c(-0.75, -0.5, -0.25, 0, 0.25),
               y_label="Marginal effect",
               theme_overrides=list(axis.title.x=element_blank())),
  
  plot_aff_pol(models[["fairly_4point_aff_pol_with_winner01"]], "aff_pol_with_winner01",
               y_limits = c(-0.75, 0.3), y_breaks = c(-0.75, -0.5, -0.25, 0, 0.25),
               theme_overrides=list(axis.text.y=element_blank(), axis.title=element_blank())),
  
  plot_aff_pol(models[["satisfied_4point_aff_pol_with_winner01"]], "aff_pol_with_winner01",
               y_limits = c(-0.75, 0.3), y_breaks = c(-0.75, -0.5, -0.25, 0, 0.25),
               theme_overrides=list(axis.text.y=element_blank(), axis.title=element_blank()))
)

# Combine figures
aff_pol_effect <- ggarrange(plotlist = plots_feeling, nrow=1,
                            widths=c(1,0.9,0.9))
aff_pol_effect <- annotate_figure(aff_pol_effect, top = textGrob("A) Effect of feelings towards the winning party", gp=gpar(cex=1)))

aff_pol_effect2 <- ggarrange(plotlist = plots_gap, nrow=1, 
                             widths=c(1,0.9,0.9))
aff_pol_effect2 <- annotate_figure(aff_pol_effect2, 
                                   top = textGrob("B) Effect of gap in feelings between their own party and the winning party", gp=gpar(cex=1)),
                                   bottom = textGrob("Election year", gp=gpar(cex=1)))

fig_4 <- ggarrange(aff_pol_effect, aff_pol_effect2, nrow=2, heights=c(0.9,1))

# Save figure
ggsave(fig_4, file="./Figures/Figure_4_effect_aff_pol_with_winner_combined.png", height=6, width=9, dpi=600, bg = "white")
```

## Figure 5: Effet of gap in feelings towards the Liberals and Conservatives by party family

```{r}
# Specify control variables
controls <- "interest + female + age_cat + educ_cat + region" 

# Estimate models
fairly_feel_family <- lm_robust(data=dat, weights=cps_weight,  se_type = "HC2",
   formula = formula(paste0("fairly_4point ~ aff_pol_libcon*party_family*Year +", controls)))
confidence_feel_family <- lm_robust(data=dat, weights=cps_weight,  se_type = "HC2",
   formula = formula(paste0("confidence_4point ~ aff_pol_libcon*party_family*Year +", controls)))
satisfied_feel_family <- lm_robust(data=dat, weights=cps_weight,  se_type = "HC2",
   formula = formula(paste0("satisfied_4point ~ aff_pol_libcon*party_family*Year +", controls)))

# Create figures (one for each outcome)
aff_pol_confidence_family <- plot_slopes(confidence_feel_family, variables = "aff_pol_libcon", condition = c("Year", "party_family"), draw=FALSE) %>% 
  ggplot(aes(x = Year, y = estimate, color = party_family, shape = party_family)) +
    geom_hline(yintercept = 0, linetype = 2) +
    geom_point(size = 2.5, position=position_dodge(0.1)) +
    geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0, position=position_dodge(0.1), key_glyph = "vline") +
    geom_line(key_glyph = "blank") +
    scale_color_manual(values = c("red3", "blue3")) +
    scale_shape_manual(values = c(17, 15)) +
    scale_y_continuous(limits = c(-0.01, 0.005),
                       breaks = c(-0.01, -0.0075, -0.005, -0.0025, 0, 0.0025, 0.005)) +
    labs(x = "Year",
         y = "Marginal effect of affective polarization",
         title = "A) Effect on confidence",
         color = NULL, shape = NULL) +
    theme_minimal() +
    theme(legend.title = element_blank(),
          legend.position = "top",
          plot.title = element_text(size = 12))

aff_pol_fairness_family <- plot_slopes(fairly_feel_family, variables = "aff_pol_libcon", condition = c("Year", "party_family"), draw=FALSE) %>% 
ggplot(aes(x = Year, y = estimate, color = party_family, shape = party_family)) +
    geom_hline(yintercept = 0, linetype = 2) +
    geom_point(size = 2.5, position=position_dodge(0.1)) +
    geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0, position=position_dodge(0.1), key_glyph = "vline") +
    geom_line(key_glyph = "blank") +
    scale_color_manual(values = c("red3", "blue3")) +
    scale_shape_manual(values = c(17, 15)) +
    scale_y_continuous(limits = c(-0.01, 0.005),
                       breaks = c(-0.01, -0.0075, -0.005, -0.0025, 0, 0.0025, 0.005)) +
  labs(x="Year",
       y = "Marginal effect of affective polarization",
       title = "B) Effect on perceived fairness")+
  theme_minimal()+
  theme(legend.title = element_blank(),
        legend.position="top",
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        plot.title=element_text(size=12))

aff_pol_satisfied_family <- plot_slopes(satisfied_feel_family, variables = "aff_pol_libcon", condition = c("Year", "party_family"), draw=FALSE) %>% 
  ggplot(aes(x = Year, y = estimate, color = party_family, shape = party_family)) +
    geom_hline(yintercept = 0, linetype = 2) +
    geom_point(size = 2.5, position=position_dodge(0.1)) +
    geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0, position=position_dodge(0.1), key_glyph = "vline") +
    geom_line(key_glyph = "blank") +
    scale_color_manual(values = c("red3", "blue3")) +
    scale_shape_manual(values = c(17, 15)) +
    scale_y_continuous(limits = c(-0.01, 0.005),
                       breaks = c(-0.01, -0.0075, -0.005, -0.0025, 0, 0.0025, 0.005)) +
  labs(x="Year",
       y = "Marginal effect of affective polarization",
       title = "C) Effect on satisfaction")+
  theme_minimal()+
  theme(legend.title = element_blank(),
        legend.position="top",
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        plot.title=element_text(size=12))

# Combine figures
fig_5 <- ggarrange(aff_pol_confidence_family, aff_pol_fairness_family, aff_pol_satisfied_family, nrow=1, widths=c(1,0.9,0.9), common.legend = TRUE)

# Save figures
ggsave(fig_5, file="./Figures/Figure_5_effect_affpol_libcon_family.png", height=4.5, width=9, dpi=600, bg = "white") 
```

## Table B1: Perceptions of election administration based on feelings towards the winning party

```{r}
## Regression table
new_rows_B1 <- tribble(~term, ~confidence_feel_win, ~fairly_feel_win, ~satisfied_feel_win,
  "Region fixed effects", "Yes", "Yes", "Yes")
attr(new_rows_B1, 'position') <- c(20)

modelsummary(list("Confidence<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$confidence_4point_feeling_winner01, 
                  "Fairness<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$fairly_4point_feeling_winner01, 
                  "Satisfaction<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$satisfied_4point_feeling_winner01),
             coef_map = c("feeling_winner01" = "Feelings winning party",
                          "Year2011" = "2011 election",
                          "Year2015" = "2015 election",
                          "Year2019" = "2019 election",
                          "Year2021" = "2021 election",
                          "feeling_winner01:Year2011" = "Feelings winning party * 2011 election",
                          "feeling_winner01:Year2015" = "Feelings winning party * 2015 election",
                          "feeling_winner01:Year2019" = "Feelings winning party * 2019 election",
                          "feeling_winner01:Year2021" = "Feelings winning party * 2021 election",
                          'vote_choiceConservative' = 'Vote Conservative',
                          'vote_choiceNDP' = 'Vote New Democrat',
                          'vote_choiceBQ' = 'Vote Bloc Québécois',
                          'vote_choiceGreen' = 'Vote Green',
                          "vote_choicePeople's Party" = "Vote People's Party",
                          'interest'="Political interest",
                          'age_cat' = 'Age', 
                          'female' = 'Female', 
                          'educ_cat' = 'Education',
                          '(Intercept)' = '(Intercept)'),
             estimate = "{estimate}&nbsp;&nbsp;{std.error}&nbsp;&nbsp;{p.value}",
             statistic = NULL,
             output = "./Tables/Table_B1.html",
             add_rows = new_rows_B1,
             gof_omit = "AIC|BIC|Std.Errors|RMSE",
             escape = FALSE)
```

## Table B2: Perceptions of election administration based on the gap between respondents’ feelings towards their own party and the winning party

```{r}
## Regression table
modelsummary(list("Confidence<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$confidence_4point_aff_pol_with_winner01, 
                  "Fairness<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$fairly_4point_aff_pol_with_winner01, 
                  "Satisfaction<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=models$satisfied_4point_aff_pol_with_winner01),
             coef_map = c("aff_pol_with_winner01" = "Affective polarization",
                          "Year2011" = "2011 election",
                          "Year2015" = "2015 election",
                          "Year2019" = "2019 election",
                          "Year2021" = "2021 election",
                          "aff_pol_with_winner01:Year2011" = "Affective polarization * 2011 election",
                          "aff_pol_with_winner01:Year2015" = "Affective polarization * 2015 election",
                          "aff_pol_with_winner01:Year2019" = "Affective polarization * 2019 election",
                          "aff_pol_with_winner01:Year2021" = "Affective polarization * 2021 election",
                          'vote_choiceConservative' = 'Vote Conservative',
                          'vote_choiceNDP' = 'Vote New Democrat',
                          'vote_choiceBQ' = 'Vote Bloc Québécois',
                          'vote_choiceGreen' = 'Vote Green',
                          "vote_choicePeople's Party" = "Vote People's Party",
                          'interest'="Political interest",
                          'age_cat' = 'Age', 
                          'female' = 'Female', 
                          'educ_cat' = 'Education',
                          '(Intercept)' = '(Intercept)'),
             estimate = "{estimate}&nbsp;&nbsp;{std.error}&nbsp;&nbsp;{p.value}",
             statistic = NULL,
             output = "./Tables/Table_B2.html",
             add_rows = new_rows_B1,
             gof_omit = "AIC|BIC|Std.Errors|RMSE",
             escape = FALSE)
```

## Table B3: Perceptions of election administration based on the absolute distance in feelings towards the Liberal Party and the Conservative Party by party family

```{r}
## Regression table
new_rows_B3 <- tribble(~term, ~fairly_feel_family, ~confidence_feel_family, ~satisfied_feel_family,
                       "Region fixed effects", "Yes", "Yes", "Yes")
attr(new_rows_B3, 'position') <- c(25)

modelsummary(list("Confidence<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=confidence_feel_family, 
                  "Fairness<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=fairly_feel_family, 
                  "Satisfaction<br>Estimate&nbsp;&nbsp;&nbsp;SE&nbsp;&nbsp;&nbsp;p-value"=satisfied_feel_family),
             coef_map = c('aff_pol_libcon' = 'Affective polarization', 
                          'party_familyRight-wing parties' = 'Right-wing', 
                          'Year2011' = '2011 election', 
                          'Year2015' = '2015 election', 
                          'Year2019' = '2019 election', 
                          "Year2021" = "2021 election", 
                          'aff_pol_libcon:party_familyRight-wing parties' = 'Affective polarization * Right-wing', 
                          'aff_pol_libcon:Year2011' = 'Affective polarization x 2011', 
                          'aff_pol_libcon:Year2015' = 'Affective polarization x 2015', 
                          'aff_pol_libcon:Year2019' = 'Affective polarization x 2019', 
                          "aff_pol_libcon:Year2021" = "Affective polarization x 2021",
                          'party_familyRight-wing parties:Year2011' = 'Right-wing x 2011', 
                          'party_familyRight-wing parties:Year2015' = 'Right-wing x 2015', 
                          'party_familyRight-wing parties:Year2019' = 'Right-wing x 2019', 
                          "party_familyRight-wing parties:Year2021" = "Right-wing x 2021",
                          'aff_pol_libcon:party_familyRight-wing parties:Year2011' = 'Affective polarization x Right-wing x 2011', 
                          'aff_pol_libcon:party_familyRight-wing parties:Year2015' = 'Affective polarization x Right-wing x 2015', 
                          'aff_pol_libcon:party_familyRight-wing parties:Year2019' = 'Affective polarization x Right-wing x 2019', 
                          "aff_pol_libcon:party_familyRight-wing parties:Year2021" = "Affective polarization x Right-wing x 2021",
                          'interest' = 'Political interest', 
                          'age_cat' = 'Age', 
                          'female' = 'Female', 
                          'educ_cat' = 'Education',
                          '(Intercept)' = '(Intercept)'),
             estimate = "{estimate}&nbsp;&nbsp;{std.error}&nbsp;&nbsp;{p.value}",
             statistic = NULL,
             output = "./Tables/Table_B3.html",
             add_rows = new_rows_B3,
             gof_omit = "AIC|BIC|Std.Errors|RMSE",
             escape = FALSE)
```

## Figure C4: Trust in election administration over time (full scale)

```{r}
# Mean perceptions of election administration by year
wt_fairly_fullscale <- svyby(~fairly, ~factor(year), design, svymean, na.rm = T) %>% 
  mutate(Variable = "Fairly") %>% 
  rename(value = fairly,
         year = `factor(year)`)
wt_confidence_fullscale <- svyby(~confidence, ~factor(year), design, svymean, na.rm = T)%>% 
  mutate(Variable = "Confidence") %>% 
  rename(value = confidence,
         year = `factor(year)`)
wt_satisfied_fullscale <- svyby(~satisfied, ~factor(year), design, svymean, na.rm = T)%>% 
  mutate(Variable = "Satisfied") %>% 
  rename(value = satisfied,
         year = `factor(year)`)

# Merge outputs
wt_time_fullscale <- rbind(wt_fairly_fullscale, wt_confidence_fullscale, wt_satisfied_fullscale) %>% 
  # Put year variable into numeric format
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Calculate confidence intervals
  lower=value-1.96*se, upper=value+1.96*se, 
  # Specify order of trust variables
  Variable = factor(Variable, levels = c("Confidence", "Fairly", "Satisfied")))

# Create figure
fig_c4 <- ggplot(wt_time_fullscale, aes(x = year_num, y = value))+
  geom_point(aes(col = Variable, shape=Variable), size = 2.5)+
  geom_line(aes(col = Variable, group = Variable))+
  geom_errorbar(aes(ymin = value-1.96*se, ymax = value+1.96*se, col = Variable, group = Variable), width = 0, size=0.8)+
  scale_y_continuous(limits = c(0, 1), breaks = c(0, 0.33, 0.67, 1),
                     labels = c(1, 2, 3, 4))+
  scale_x_continuous(limits = c(2008, 2021), breaks = c(2008:2021),
                     labels = c("2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017",
                                "2018", "2019", "2020", "2021"))+
  scale_color_manual(values = c("red3", "blue3", "green4"), 
                     labels = c("Confidence in\nElections Canada", "Election was\nadministered fairly", "Satisfied with the way Elections\n Canada runs elections"))+
  scale_shape_manual(values=c(15:17), 
                     labels = c("Confidence in\nElections Canada", "Election was\nadministered fairly", "Satisfied with the way Elections\n Canada runs elections"))+
  labs(x = "Year",
       y = "Weighted mean (1-4)", 
       color="",
       shape="")+
  theme_minimal()+
  theme(legend.position = "top",
        panel.grid.minor.x = element_blank())

# Save figure
ggsave(fig_c4, file="./Figures/Figure_C4_time_plot_fullscale.png", height = 4.5)
```

## Figure C5: Trust in election administration over time by ideology and vote choice (full scale)

```{r}
# Perceptions of election administration by ideology
confidence_ideol_fullscale <- summarize_weighted(data = dat, dv = "confidence", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Confidence")

fairly_ideol_fullscale <- summarize_weighted(data = dat, dv = "fairly", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Fairly")

satisfied_ideol_fullscale <- summarize_weighted(data = dat, dv = "satisfied", ivs = c("year", "ideol2"),  weight_var = "cps_weight", var_label = "Satisfied")

# Merge outputs
time_ideol_fullscale <- rbind(satisfied_ideol_fullscale, confidence_ideol_fullscale, fairly_ideol_fullscale) %>% 
  # Put year variable in numeric format
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Specify order of ideology
  ideol2 = factor(ideol2, levels = c("Left (0-3)", "Moderate (4-6)", "Right (7-10)")))

# Create figure (ideology panel)
plot_ideol_fullscale <- ggplot(time_ideol_fullscale, aes(x=year_num, y = value, col = ideol2, shape=ideol2))+
  geom_point(size=2, position=position_dodge(0.7))+
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, alpha=0.3, position=position_dodge(0.7))+
  geom_line(aes(group=ideol2), position=position_dodge(0.7))+
  facet_wrap(~var)+
  scale_y_continuous(limits = c(0.33, 1), breaks = c(0.33, 0.67, 1),
                     labels = c(2,3,4))+
  scale_x_continuous(limits = c(2007.5, 2021.5), breaks = c(2008:2021),
                     labels = c("08", "09", "10", "11", "12", "13", "14", "15", "16", "17",
                                "18", "19", "20", "21"))+
  scale_color_manual(values = c("firebrick4","darkgrey", "darkblue"))+
  scale_shape_manual(values=c(2,1,0))+
  labs(x = "Year",
       y = "Weighted mean (1-4)", 
       color="",
       shape="",
       title="Ideology")+
  theme_minimal()+
  theme(legend.position = "right",
        plot.title = element_text(size=12),
        axis.title.x=element_blank(),
        strip.text=element_text(size=11),
        panel.grid.minor = element_blank())

# Perceptions of election administration by vote choice
confidence_vote_fullscale <- summarize_weighted(data = dat, dv = "confidence", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Confidence")

fairly_vote_fullscale <- summarize_weighted(data = dat, dv = "fairly", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Fairly")

satisfied_vote_fullscale <- summarize_weighted(data = dat, dv = "satisfied", ivs = c("year", "vote_choice"),  weight_var = "cps_weight", var_label = "Satisfied")

# Merge outputs
time_vote_fullscale <- rbind(satisfied_vote_fullscale, confidence_vote_fullscale, fairly_vote_fullscale) %>% 
  # Put year variable in numeric format
  mutate(year_num = case_when(
    year=="2008" ~ 2008,
    year=="2011" ~ 2011,
    year=="2015" ~ 2015,
    year=="2019" ~ 2019,
    year=="2021" ~ 2021
  ),
  # Identify governing parties
  alpha=ifelse(vote_choice %in% c("Liberal", "Conservative"), 1, 0))

# Create figure (vote choice panel)
plot_vote_fullscale <- ggplot(time_vote_fullscale, aes(x=year_num, y=value, col=vote_choice, shape=vote_choice)) +
  geom_point(size=2, position=position_dodge(0.7)) +
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, position=position_dodge(0.7)) +
  geom_line(aes(group=vote_choice), position=position_dodge(0.7)) +
  facet_wrap(~var) +
  scale_y_continuous(limits = c(0.33, 1), breaks = c(0.33, 0.67, 1),
                     labels = c(2,3,4))+
  scale_x_continuous(limits = c(2007.5, 2021.5), breaks = c(2008:2021),
                     labels = c("08", "09", "10", "11", "12", "13", "14", "15", "16", "17",
                                "18", "19", "20", "21"))+
  scale_color_manual(values=new_colors,
                     labels=c("Liberal", "Conservative", "New Democrat", "Bloc Québécois", "Green", "People's Party")) +
  scale_shape_manual(values=c(16, 15, 17, 18, 20, 8),
                     labels=c("Liberal", "Conservative", "New Democrat", "Bloc Québécois", "Green", "People's Party")) +
  labs(x = "Year",
       y = "Weighted mean (1-4)", 
       color="",
       shape="",
       title="Vote choice")+
  theme_minimal() +
  theme(legend.position="right",
        plot.title=element_text(size=12),
        strip.text=element_blank(),
        panel.grid.minor=element_blank())

fig_c5 <- plot_ideol_fullscale/plot_vote_fullscale

ggsave(fig_c5, file="./Figures/Figure_C5_over_time_party_ideol_fullscale.png", bg="white", height=7, width=10)
```

## Figure C6: Effect of affective polarization by party

```{r}
# Specify model components
controls <- "female + age_cat + educ_cat + interest + region"
interaction_formula <- "aff_pol_with_winner01*vote_choice*Year"
ovrl_formula <- "aff_pol_with_winner01*Year + vote_choice"
weight_var <- "cps_weight"
outcomes <- c("fairly_4point", "confidence_4point", "satisfied_4point")

# Function to run lm_robust
run_lm <- function(outcome, formula, data) {
  lm_robust(
    formula = as.formula(paste0(outcome, " ~ ", formula)),
    data = data,
    weights = cps_weight,
    se_type = "HC2"
  )
}

# Run models
models <- lapply(outcomes, function(y) {
  list(
    interaction = run_lm(y, paste(controls, interaction_formula, sep=" + "), dat),
    overall = run_lm(y, paste(controls, ovrl_formula, sep=" + "), dat)
  )
})
names(models) <- outcomes

# Function to process slopes and create figure
plot_aff_pol <- function(model_list, outcome_title) {
  
  # Interaction slopes
  slopes <- plot_slopes(model_list$interaction, "aff_pol_with_winner01", c("Year", "vote_choice"), draw=F) %>%
    # Filter out parties that won the election or didn't exist
    filter(!(Year %in% c("2008", "2011") & vote_choice %in% c("Conservative", "People's Party")) &
             !(Year == "2015" & vote_choice %in% c("Liberal", "People's Party")) &
             !(Year %in% c("2019", "2021") & vote_choice == "Liberal")) %>%
    select(estimate, conf.low, conf.high, vote_choice, Year)
  
  # Overall slopes
  slopes_ovrl <- plot_slopes(model_list$overall, "aff_pol_with_winner01", "Year", draw=F) %>%
    mutate(vote_choice = "Combined effect") %>%
    select(estimate, conf.low, conf.high, vote_choice, Year) %>%
    rbind(slopes) %>%
    mutate(vote_choice = factor(vote_choice, levels=c("Liberal", "Conservative", "NDP", "BQ", "Green", "People's Party", "Combined effect")))
  
  # Plot
  ggplot(slopes_ovrl, aes(x=Year, y=estimate, ymin=conf.low, ymax=conf.high, col=vote_choice, shape=vote_choice)) +
    geom_hline(yintercept=0, linetype=2) +
    geom_point(size=2.5, position=position_dodge(0.5)) +
    geom_errorbar(width=0, position=position_dodge(0.5)) +
    scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple", "black"),
                       labels=c("Liberals", "Conservatives", "NDP", "Bloc Québécois", "Green", "People's Party", "Combined effect")) +
    scale_shape_manual(values=c(16, 15, 17, 18, 20, 8, 0),
                       labels=c("Liberals", "Conservatives", "NDP", "Bloc Québécois", "Green", "People's Party", "Combined effect")) +
    scale_y_continuous(limits=c(-2.2,2)) +
    labs(x="Year", y="Marginal effect of affective polarization", title=outcome_title) +
    theme_minimal() +
    theme(legend.title = element_blank(),
          legend.position="top",
          plot.title=element_text(size=12))
}

# Generate figures
plots <- list(
  "A) Effect on confidence" = plot_aff_pol(models$confidence_4point, "A) Effect on confidence"),
  "B) Effect on perceived fairness" = plot_aff_pol(models$fairly_4point, "B) Effect on perceived fairness"),
  "C) Effect on satisfaction" = plot_aff_pol(models$satisfied_4point, "C) Effect on satisfaction")
)

# Merge figures
fig_c6 <- ggarrange(plots[[1]], plots[[2]], plots[[3]], nrow=1, widths=c(1,0.9,0.9), common.legend=T)

# Save figure
ggsave(fig_c6, file="./Figures/Figure_C6_effect_aff_pol_with_winner.png", bg="white", height=4.5, width=11)
```

## Figure C7: Effect of spread in feelings by party family

```{r}
# Outcomes
outcomes <- c("confidence_4point", "fairly_4point", "satisfied_4point")
titles <- c(
  "A) Effect on confidence",
  "B) Effect on perceived fairness",
  "C) Effect on satisfaction"
)

# Function to run lm_robust
run_spread_lm <- function(outcome) {
  lm_robust(
    formula = as.formula(paste0(outcome, " ~ spread_affect*party_family*Year + ", basic_controls)),
    data = dat,
    weights = cps_weight,
    se_type = "HC2"
  )
}

# Run models
models <- lapply(outcomes, run_spread_lm)
names(models) <- outcomes

# Function to plot slopes
plot_spread <- function(model, title) {
  plot_slopes(model, variables = "spread_affect", condition = c("Year", "party_family"), draw=FALSE) %>% 
    ggplot(aes(x = Year, y = estimate, color = party_family, shape = party_family)) +
    geom_hline(yintercept = 0, linetype = 2) +
    geom_point(size = 2.5, position=position_dodge(0.1)) +
    geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0, position=position_dodge(0.1), key_glyph = "vline") +
    scale_color_manual(values = c("red3", "blue3")) +
    scale_shape_manual(values = c(17, 15)) +
    scale_y_continuous(limits=c(-0.056,0.075), breaks=c(-0.05, -0.025, 0, 0.025, 0.05, 0.075)) +
    labs(x="Year", y="Marginal effect of affective polarization", title=title) +
    theme_minimal() +
    theme(
      legend.title = element_blank(),
      legend.position = "top",
      axis.title.y = if(title=="A) Effect on confidence") element_text() else element_blank(),
      axis.text.y  = if(title=="A) Effect on confidence") element_text() else element_blank(),
      plot.title = element_text(size=12)
    )
}

# Generate figures
plots <- mapply(plot_spread, models, titles, SIMPLIFY = FALSE)

# Merge figures
fig_c7 <- ggarrange(plots[[1]], plots[[2]], plots[[3]], nrow=1, common.legend=T, widths=c(1,0.9,0.9))

# Save figure
ggsave(fig_c7, file="./Figures/Figure_C7_effect_spread_family.png", bg="white", height=4.5, width=9)
```


## Figure C8: Trust in mail-in ballots

```{r}
mailin_vote <- summarize_weighted(data = ces21, dv = "mail_distrust01", ivs = c("vote_choice"),  weight_var = "cps_weight", var_label = "Low trust in mail-in ballots") %>% 
  mutate(
    vote_choice = case_when(
      vote_choice=="Liberal" ~ "\nLiberal",
      vote_choice=="Conservative" ~ "Conservative",
      vote_choice=="NDP" ~ "\nNew\nDemocrat",
      vote_choice=="BQ" ~ "Bloc\nQuébécois",
      vote_choice=="Green" ~ "Green",
      vote_choice=="People's Party" ~ "People's\nParty"
    ),
    vote_choice=factor(vote_choice, levels=c("\nLiberal", "Conservative", "\nNew\nDemocrat", "Bloc\nQuébécois", "Green", "People's\nParty")))%>% 
  ggplot(aes(x=vote_choice, y=value, ymin=lower, ymax=upper, col=vote_choice, shape=vote_choice))+
  geom_point(size=2.5)+
  geom_errorbar(width=0, size=0.8)+
  scale_y_continuous(limits = c(0, 0.8), breaks = c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8),
                     labels = percent_format(accuracy = 1))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"))+
  scale_shape_manual(values = c(16, 15, 17, 18, 20, 8))+
  labs(x="Vote choice",
       y="Weighted percentage with low trust in mail-in ballots",
       title="A) By vote choice")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12))

mailin_ideol <- summarize_weighted(data = ces21, dv = "mail_distrust01", ivs = c("ideol"),  weight_var = "cps_weight", var_label = "Low trust in mail-in ballots") %>% 
  mutate(
    ideol3 = case_when(
      ideol %in% c(0,1,2,3) ~ "Left",
      ideol %in% c(4,5,6) ~ "Moderate", 
      ideol %in% c(7,8,9,10) ~ "Right"),
    ideol_char=case_when(
      ideol == 0 ~ "0\n\n",
      ideol == 1 ~ "1\n\n",
      ideol == 2 ~ "2\n\n",
      ideol == 3 ~ "3\n\n",
      ideol == 4 ~ "4\n\n",
      ideol == 5 ~ "5\n\n",
      ideol == 6 ~ "6\n\n",
      ideol == 7 ~ "7\n\n",
      ideol == 8 ~ "8\n\n",
      ideol == 9 ~ "9\n\n",
      ideol == 10 ~ "10\n\n",
    ),
    ideol_char=factor(ideol_char, levels=c("0\n\n","1\n\n","2\n\n","3\n\n","4\n\n","5\n\n",
                                           "6\n\n","7\n\n","8\n\n","9\n\n","10\n\n"))) %>% 
  ggplot(aes(x=ideol_char, y=value, ymin=lower, ymax=upper, col=ideol3, shape=ideol3))+
  geom_point(size=2.5)+
  geom_errorbar(width=0, size=0.8)+
  scale_y_continuous(limits = c(0, 0.8), breaks = c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8),
                     labels = percent_format(accuracy = 1))+
  scale_color_manual(values = c("red4", "darkgrey", "blue4"))+
  scale_shape_manual(values = c(2,1,0))+
  labs(x="Left-right ideology (0-10)",
       y="Weighted percentage with low trust in mail-in ballots",
       title="B) By ideology")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12),
        axis.title.y=element_blank(),
        axis.text.y=element_blank())

fig_c8 <- ggarrange(mailin_vote, mailin_ideol, nrow=1, widths = c(1.2,1))
 
ggsave(fig_c8, file="./Figures/Figure_C8_mail_ces.png", bg="white", height=4, width=7.5)
```

## Figure D1: Satisfaction with voting experiences

```{r}
# Recode variables
ces21 <- ces21 %>% 
  mutate(
    ideol2 = case_when(
      ideol %in% c(0:3) ~ "Left\n(0-3)",
      ideol %in% c(4:6) ~ "Moderate\n(4-6)",
      ideol %in% c(7:10) ~ "Right\n(7-10)",
      TRUE ~ NA_character_
    ))

# Subset data to those who have voted
dat_voted2021 <- ces21 %>% 
  filter(!is.na(pes_weight) & turnout == 1)
design_voted2021 <- svydesign(ids=~1, data=dat_voted2021, weights = dat_voted2021$pes_weight)

# Satisfaction with voting experience by vote choice
exp_ideol <- svyby(~satisf_voting01, ~ideol2, design_voted2021, svymean, na.rm = T) 
exp_vote <- svyby(~satisf_voting01, ~vote_choice, design_voted2021, svymean, na.rm = T) %>% 
  mutate(vote_choice = factor(vote_choice, 
                              levels=c("Liberal", "Conservative", "NDP", 
                                       "BQ", "Green", "People's Party"),
                              labels = c("Liberal", "Conservative", "New\nDemocrat",
                                         "Bloc\nQuébécois", "Green", "People's\nParty")))

# Create figure (ideology panel)
exp_ideol_plot <- ggplot(exp_ideol, aes(x=ideol2, y=satisf_voting01, ymin=satisf_voting01-1.96*se, ymax=satisf_voting01+1.96*se, col=ideol2, shape=ideol2))+
  geom_point(stat="identity", size=2.5)+
  geom_errorbar(width=0, size=0.8)+
  scale_color_manual(values=c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values = c(2,1,0))+
  scale_y_continuous(limits = c(0.75, 1.01), breaks = c(0.75, 0.8, 0.85, 0.9, 0.95, 1),
                     labels = percent_format(accuracy = 1))+
  labs(x="Ideology", 
       y="Percentage satisfied with voting experience",
       title="A) Ideology")+
  theme_minimal()+
  theme(axis.title = element_text(size=11.5),
        axis.text = element_text(size=10.5),
        legend.position="none")

# Create figure (vote choice panel)
exp_vote_plot <- ggplot(exp_vote, aes(x=vote_choice, y=satisf_voting01, ymin=satisf_voting01-1.96*se, ymax=satisf_voting01+1.96*se, col=vote_choice, shape=vote_choice))+
  geom_point(stat="identity", size=2.5)+
  geom_errorbar(width=0, size=0.8)+
  scale_y_continuous(limits = c(0.75, 1.01), breaks = c(0.75, 0.8, 0.85, 0.9, 0.95, 1),
                     labels = percent_format(accuracy = 1))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"))+
  scale_shape_manual(values = c(16, 15, 17, 18, 20, 8))+
  labs(x="Vote choice", 
       y="Percentage satisfied with voting experience",
       title="B) Vote choice")+
  theme_minimal()+
  theme(axis.title.x = element_text(size=11.5),
        axis.text.x = element_text(size=10.5),
        axis.title.y= element_blank(),
        axis.text.y = element_blank(),
        legend.position="none")

# Merge figures
fig_d1 <- ggarrange(exp_ideol_plot, exp_vote_plot, nrow=1, widths=c(1,1.3))

# Save figure
ggsave(fig_d1, file="./Figures/Figure_D1_voting_exp.png", bg="white", height=4, width=9)
```

## Figure D2: Satisfaction with voting experiences (full scale)

```{r}
# Satisfaction with voting experience by vote choice (full scale)
exp_ideol_fullscale <- svyby(~satisf_voting, ~ideol2, design_voted2021, svymean, na.rm = T)
exp_vote_fullscale <- svyby(~satisf_voting, ~vote_choice, design_voted2021, svymean, na.rm = T) %>% 
  mutate(vote_choice = factor(vote_choice, 
                              levels=c("Liberal", "Conservative", "NDP", 
                                       "BQ", "Green", "People's Party"),
                              labels = c("Liberal", "Conservative", "New\nDemocrat",
                                         "Bloc\nQuébécois", "Green", "People's\nParty")))

# Create figure (ideology panel)
exp_ideol_plot_fullscale <- ggplot(exp_ideol_fullscale, aes(x=ideol2, y=satisf_voting, ymin=satisf_voting-1.96*se, ymax=satisf_voting+1.96*se, col=ideol2, shape=ideol2))+
  geom_point(stat="identity", size=2.5)+
  geom_errorbar(width=0, size=0.8)+
    scale_color_manual(values=c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values = c(2,1,0))+
  scale_y_continuous(limits = c(0,1), breaks = c(0, 0.33, 0.67, 1),
                     labels = c("1-Very dissatisfied", "2-Somewhat dissatisfied",
                                "3-Somewhat satisfied", "4-Very satisfied"))+
  labs(x="Ideology", 
       y="Mean satisfaction with voting experience",
       title="A) Ideology")+
  theme_minimal()+
  theme(axis.title = element_text(size=11.5),
        axis.text = element_text(size=10.5),
        legend.position="none")

# Create figure (vote choice panel)
exp_vote_plot_fullscale <- ggplot(exp_vote_fullscale, aes(x=vote_choice, y=satisf_voting, ymin=satisf_voting-1.96*se, ymax=satisf_voting+1.96*se, col=vote_choice, shape=vote_choice))+
  geom_point(stat="identity", size=2.5)+
  geom_errorbar(width=0, size=0.8)+
  scale_y_continuous(limits = c(0,1), breaks = c(0, 0.33, 0.67, 1),
                     labels = c("1-Very dissatisfied", "2-Somewhat dissatisfied",
                                "3-Somewhat satisfied", "4-Very satisfied"))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"))+
  scale_shape_manual(values = c(16, 15, 17, 18, 20, 8))+
  labs(x="Vote choice", 
       y="Percentage satisfied with voting experience",
       title="B) Vote choice")+
  theme_minimal()+
  theme(axis.title.x = element_text(size=11.5),
        axis.text.x = element_text(size=10.5),
        axis.title.y= element_blank(),
        axis.text.y = element_blank(),
        legend.position="none")

# Merge figures
fig_d2 <- ggarrange(exp_ideol_plot_fullscale, exp_vote_plot_fullscale, nrow=1, widths=c(1,1.3))

# Save figure
ggsave(fig_d2, file="./Figures/Figure_D2_voting_exp_fullscale.png", bg="white", height=4, width=9)
```

## Figure D3: Trust in institutions by partisanship

```{r}
# Calculate trust in institutions by vote choice and year
trust_institutions_vote <- dat %>%
  select(year, vote_choice, confidence01,  trust_pub_serv01, trust_media01, trust_fedgov01, cps_weight) %>%
  na.omit() %>%
  pivot_longer(
    cols = c(confidence01, trust_pub_serv01, trust_media01, trust_fedgov01),
    names_to = "var",
    values_to = "value_raw"
  ) %>%
  group_by(year, vote_choice, var) %>%
  dplyr::summarize(
    value = weighted.mean(value_raw, w = cps_weight),
    sd = sqrt(wtd.var(value_raw, cps_weight)),
    n = n(),
    .groups = "drop"
  ) %>%
  mutate(
    se = sd / sqrt(n),
    lower = value - 1.96 * se,
    upper = value + 1.96 * se,
    year_num = case_when(
      year == "2008" ~ 2008,
      year == "2011" ~ 2011,
      year == "2015" ~ 2015,
      year == "2019" ~ 2019,
      year == "2021" ~ 2021
    ),
    var = case_when(
      var == "confidence01" ~ "Elections Canada",
      var == "trust_fedgov01" ~ "Federal government",
      var == "trust_media01" ~ "Media",
      var == "trust_pub_serv01" ~ "Public service" 
    )
  ) %>% 
  filter(vote_choice %in% c("Liberal", "Conservative"))

# Create figure
fig_d3 <- ggplot(trust_institutions_vote, aes(x=year_num, y = value, col = vote_choice, shape = vote_choice))+
  geom_point(position=position_dodge(0.4))+
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, position=position_dodge(0.4))+
  geom_line(aes(group=vote_choice), position=position_dodge(0.4))+
  facet_wrap(~var)+
  scale_y_continuous(limits = c(0, 1), breaks = c(0, 0.2, 0.4, 0.6, 0.8, 1),
                     labels = percent_format(accuracy = 1))+
  scale_x_continuous(limits = c(2007.8, 2021.2), breaks = c(2008, 2010, 2012, 2014, 2016, 2018, 2020),
                     labels = c("2008", "2010", "2012", "2014", "2016", "2018", "2020"))+
scale_color_manual(values = c("red3","blue3"))+
  scale_shape_manual(values = c(16, 15))+
  scale_alpha_manual(values=c(0.5, 1), labels=c("No", "Yes"))+
  labs(x = "Year",
       y = "Percentage who have \"Quite a lot\" or \"A great deal\" of confidence",
       color="",
       shape="")+
  guides(alpha="none")+
  theme_minimal()+
  theme(legend.position = "top",
        plot.title=element_text(size=12),
        strip.text=element_text(size=10),
        panel.grid.minor = element_blank())

# Save figure
ggsave(fig_d3, file="./Figures/Figure_D3_trust_institutions_vote_libcon.png", bg="white", height=5)
```

## Figure D4: Trust in institutions by ideology

```{r}
# Calculate trust in institutions by ideology and year
trust_institutions <- dat %>%
  select(year, ideol2, confidence01,  trust_pub_serv01, trust_media01, trust_fedgov01, cps_weight) %>%
  na.omit() %>%
  pivot_longer(
    cols = c(confidence01, trust_pub_serv01, trust_media01, trust_fedgov01),
    names_to = "var",
    values_to = "value_raw"
  ) %>%
  group_by(year, ideol2, var) %>%
  dplyr::summarize(
    value = weighted.mean(value_raw, w = cps_weight),
    sd = sqrt(wtd.var(value_raw, cps_weight)),
    n = n(),
    .groups = "drop"
  ) %>%
  mutate(
    se = sd / sqrt(n),
    lower = value - 1.96 * se,
    upper = value + 1.96 * se,
    year_num = case_when(
      year == "2008" ~ 2008,
      year == "2011" ~ 2011,
      year == "2015" ~ 2015,
      year == "2019" ~ 2019,
      year == "2021" ~ 2021
    ),
    ideol2 = factor(ideol2, levels = c("Left (0-3)", "Moderate (4-6)", "Right (7-10)")),
    var = case_when(
      var == "confidence01" ~ "Elections Canada",
      var == "trust_fedgov01" ~ "Federal government",
      var == "trust_media01" ~ "Media",
      var == "trust_pub_serv01" ~ "Public service" 
    )
  )

# Create figure
fig_d4 <- ggplot(trust_institutions, aes(x=year_num, y = value, col = ideol2, shape=ideol2))+
  geom_point(position=position_dodge(0.4))+
  geom_errorbar(aes(ymin=lower, ymax=upper), width=0, position=position_dodge(0.4))+
  geom_line(aes(group=ideol2), position=position_dodge(0.4))+
  facet_wrap(~var)+
  scale_y_continuous(limits = c(0.1, 1), breaks = c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     labels = percent_format(accuracy = 1))+
  scale_x_continuous(limits = c(2007.8, 2021.2), breaks = c(2008, 2010, 2012, 2014, 2016, 2018, 2020),
                     labels = c("2008", "2010", "2012", "2014", "2016", "2018", "2020"))+
  scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values = c(17,16,15))+
  labs(x = "Year",
       y = "Percentage who have \"Quite a lot\" or \"A great deal\" of confidence",
       color="", shape="")+
  theme_minimal()+
  theme(legend.position = "top",
        plot.title=element_text(size=12),
        strip.text=element_text(size=10),
        panel.grid.minor = element_blank())

# Save figure
ggsave(fig_d4, file="./Figures/Figure_D4_trust_institutions_ideol.png", bg="white", height=5)
```

## Figure D5: Trust in election administration by trust in government

```{r}
fairly_trustfed <-  summarize_weighted(data = dat, dv = "fairly01", ivs = c("year", "trust_fedgov01", "ideol2"),  weight_var = "cps_weight", var_label = "Fairly") %>% 
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_fedgov01), alpha = factor(trust_fedgov01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_fedgov01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Trust in federal government",
       alpha="Trust in federal government",
       y=NULL,
       x=NULL,
       title="Elections Canada administered the election fairly")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(axis.text.x = element_blank())

confidence_trustfed <-  summarize_weighted(data = dat, dv = "confidence01", ivs = c("year", "trust_fedgov01", "ideol2"),  weight_var = "cps_weight", var_label = "Confidence") %>% 
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_fedgov01), alpha = factor(trust_fedgov01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_fedgov01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Trust in federal government",
       alpha="Trust in federal government",
       y=NULL,
       x=NULL,
       title="Confidence in Elections Canada")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(axis.text.x = element_blank(),
        strip.text=element_blank())

satisfied_trustfed <-  summarize_weighted(data = dat, dv = "satisfied01", ivs = c("year", "trust_fedgov01", "ideol2"),  weight_var = "cps_weight", var_label = "Satisfied") %>% 
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_fedgov01), alpha = factor(trust_fedgov01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_fedgov01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Trust in federal government",
       alpha="Trust in federal government",
       y=NULL,
       x=NULL,
       title="Satisfied with the way Elections Canada runs elections")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(strip.text=element_blank())

fig_d5 <- ggarrange(fairly_trustfed, confidence_trustfed, satisfied_trustfed, nrow=3, common.legend=TRUE, heights=c(1.15, 1, 1.1))

ggsave(fig_d5, file="./Figures/Figure_D5_by_trust_fedgov.png", bg="white", height=7, width=7)
```

## Figure D6: Trust in election administration by trust in the media

```{r}
fairly_trustmed <-  summarize_weighted(data = dat, dv = "fairly01", ivs = c("year", "trust_media01", "ideol2"),  weight_var = "cps_weight", var_label = "Fairly") %>% 
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_media01), alpha = factor(trust_media01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_media01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1.02),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Media trust",
       alpha="Media trust",
       y=NULL,
       x=NULL,
       title="Elections Canada administered the election fairly")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(axis.text.x = element_blank())

confidence_trustmed <-  summarize_weighted(data = dat, dv = "confidence01", ivs = c("year", "trust_media01", "ideol2"),  weight_var = "cps_weight", var_label = "Confidence") %>%  
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_media01), alpha = factor(trust_media01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_media01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1.02),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Media trust",
       alpha="Media trust",
       y=NULL,
       x=NULL,
       title="Confidence in Elections Canada")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(axis.text.x = element_blank(),
        strip.text=element_blank())
  
satisfied_trustmed <-  summarize_weighted(data = dat, dv = "satisfied01", ivs = c("year", "trust_media01", "ideol2"),  weight_var = "cps_weight", var_label = "Satisfied") %>% 
ggplot(aes(x = year, y = value, ymin=lower, ymax=upper,
           col = ideol2, shape = factor(trust_media01), alpha = factor(trust_media01))) +
  geom_point(position=position_dodge(0.1), size=2) +
   geom_errorbar(width=0, position=position_dodge(0.1))+
  geom_line(aes(group=factor(trust_media01)), position=position_dodge(0.1))+
  scale_alpha_manual(values = c(0.45, 1), labels = c("Low", "High")) +
  scale_shape_manual(values = c(17, 19), labels = c("Low", "High")) +
  scale_y_continuous(label=percent_format(accuracy=1),
                     limits=c(0.45, 1.02),
                     breaks=c(0.5, 0.6, 0.7, 0.8, 0.9, 1))+
    scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  labs(shape="Media trust",
       alpha="Media trust",
       y=NULL,
       x=NULL,
       title="Satisfiied with the way Elections Canada runs elections")+
  guides(color="none")+
  facet_wrap(~ideol2, nrow=1)+
  theme_minimal()+
  theme(strip.text=element_blank())

fig_d6 <- ggarrange(fairly_trustmed, confidence_trustmed, satisfied_trustmed, nrow=3, common.legend=TRUE, heights=c(1.15, 1, 1.1))

ggsave(fig_d6, file="./Figures/Figure_D6_by_trust_media.png", bg="white", height=7, width=7)
```

## Figure D8: Confidence that elections are safe from foreign interference by vote choice and ideology

```{r}
# Calculate perceptions of foreign interference by vote choice
foreign_desc_vote <-  summarize_weighted(data = dat %>% filter(keyword_interference_confident == 1), dv = "safe_interference01", ivs = c( "vote_choice", "year"),  weight_var = "cps_weight", var_label = "Our elections are safe from foreign interference") %>% 
  mutate(
    vote_choice = case_when(
      vote_choice=="Liberal" ~ "Liberal",
      vote_choice=="Conservative" ~ "Conservative",
      vote_choice=="NDP" ~ "New\nDemocrat",
      vote_choice=="BQ" ~ "Bloc\nQuébécois",
      vote_choice=="Green" ~ "Green",
      vote_choice=="People's Party" ~ "People's\nParty"
    ),
    vote_choice=factor(vote_choice, levels=c("Liberal", "Conservative", "New\nDemocrat", "Bloc\nQuébécois", "Green", "People's\nParty"))) 

# Create figure (vote choice panel)
foreign_plot1 <- ggplot(foreign_desc_vote, aes(x=vote_choice, y=value, ymin=lower, ymax=upper, col=vote_choice, shape=vote_choice, alpha=year))+
  geom_point(size=2.5, position=position_dodge(0.2))+
  geom_errorbar(width=0, position=position_dodge(0.2))+
  scale_y_continuous(limits = c(0.2, 1), 
                     breaks = c(0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     labels = percent_format(accuracy = 1))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"))+
  scale_shape_manual(values = c(16, 15, 17, 18, 20, 8))+
  scale_alpha_manual(values=c(0.4,1))+
  labs(x="Vote choice",
       y="Weighted percentage of respondents",
       title="A) Vote choice",
       alpha="Election")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12))

# Calculate perceptions of foreign interference by ideology
foreign_desc_ideol <-  summarize_weighted(data = dat %>% filter(keyword_interference_confident == 1), dv = "safe_interference01", ivs = c( "ideol2", "year"),  weight_var = "cps_weight", var_label = "Our elections are safe from foreign interference")

# Create figure (ideology panel)
foreign_plot_ideol <- ggplot(foreign_desc_ideol, aes(x=ideol2, y=value, ymin=lower, ymax=upper, col=ideol2, shape=ideol2, alpha=year))+
  geom_point(size=2.5, position=position_dodge(0.2))+
  geom_errorbar(width=0, position=position_dodge(0.2))+
  scale_y_continuous(limits = c(0.2, 1), 
                     breaks = c(0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
                     labels = percent_format(accuracy = 1))+
  scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values = c(2,1,0))+
  scale_alpha_manual(values=c(0.4,1))+
  labs(x="Ideology",
       y="Weighted percentage of respondents",
       title="B) Ideology",
       alpha="Election")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12),
        axis.title.y=element_blank(),
        axis.text.y=element_blank())

# Merge figures
fig_d8 <- ggarrange(foreign_plot1, foreign_plot_ideol, common.legend = TRUE, widths = c(1.5, 1))

# Save figure
ggsave(fig_d8, file="./Figures/Figure_D8_foreign_interference.png", bg="white", height=4, width=9)
```

## Figure D9: Confidence that elections are safe from foreign interference by vote choice and ideology (full scale)

```{r}
# Calculate perceptions of foreign interference by vote choice (full scale)
foreign_desc_vote_fullscale <-  summarize_weighted(data = dat %>% filter(keyword_interference_confident == 1), dv = "safe_interference", ivs = c( "vote_choice", "year"),  weight_var = "cps_weight", var_label = "Our elections are safe from foreign interference") %>% 
  mutate(
    vote_choice = case_when(
      vote_choice=="Liberal" ~ "Liberal",
      vote_choice=="Conservative" ~ "Conservative",
      vote_choice=="NDP" ~ "New\nDemocrat",
      vote_choice=="BQ" ~ "Bloc\nQuébécois",
      vote_choice=="Green" ~ "Green",
      vote_choice=="People's Party" ~ "People's\nParty"
    ),
    vote_choice=factor(vote_choice, levels=c("Liberal", "Conservative", "New\nDemocrat", "Bloc\nQuébécois", "Green", "People's\nParty"))) 

# Create figure (vote choice panel)
foreign_plot1_fullscale <- ggplot(foreign_desc_vote_fullscale, aes(x=vote_choice, y=value, ymin=lower, ymax=upper, col=vote_choice, shape=vote_choice, alpha=year))+
  geom_point(size=2.5, position=position_dodge(0.2))+
  geom_errorbar(width=0, position=position_dodge(0.2))+
  scale_y_continuous(limits = c(0,1), 
                     breaks = c(0, 0.33, 0.67, 1),
                     labels = c("1-Not at all\nconfident", "2-Not very\nconfident",
                                "3-Somewhat\nconfident", "4-Very\nconfident"))+
  scale_color_manual(values = c("red3","blue3", "orange", "cyan3", "green4", "purple"))+
  scale_shape_manual(values = c(16, 15, 17, 18, 20, 8))+
  scale_alpha_manual(values=c(0.4,1))+
  labs(x="Vote choice",
       y="Weighted means",
       title="A) Vote choice",
       alpha="Election")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12))

# Calculate perceptions of foreign interference by ideology
foreign_desc_ideol_fullscale <-  summarize_weighted(data = dat %>% filter(keyword_interference_confident == 1), dv = "safe_interference", ivs = c( "ideol2", "year"),  weight_var = "cps_weight", var_label = "Our elections are safe from foreign interference")
  
foreign_plot_ideol_fullscale <- ggplot(foreign_desc_ideol_fullscale, aes(x=ideol2, y=value, ymin=lower, ymax=upper, col=ideol2, shape=ideol2, alpha=year))+
  geom_point(size=2.5, position=position_dodge(0.2))+
  geom_errorbar(width=0, position=position_dodge(0.2))+
  scale_y_continuous(limits = c(0,1), 
                     breaks = c(0, 0.33, 0.67, 1),
                     labels = c("1-Not at all\nconfident", "2-Not very\nconfident",
                                "3-Somewhat\nconfident", "4-Very\nconfident"))+
  scale_color_manual(values = c("red4","darkgrey", "blue4"))+
  scale_shape_manual(values = c(2,1,0))+
  scale_alpha_manual(values=c(0.4,1))+
  labs(x="Ideology",
       y="Weighted percentage of respondents",
       title="B) Ideology",
       alpha="Election")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(legend.position="top",
        plot.title = element_text(size=12),
        axis.title.y=element_blank(),
        axis.text.y=element_blank())

fig_d9 <- ggarrange(foreign_plot1_fullscale, foreign_plot_ideol_fullscale, common.legend = TRUE, widths = c(1.5, 1))

ggsave(fig_d9, file="./Figures/Figure_D9_foreign_interference_fullscale.png", bg="white", height=4, width=9)
```

